Add files from breeze10
This commit is contained in:
parent
4b084789fd
commit
8fb2644d49
45 changed files with 6935 additions and 0 deletions
124
CMakeLists.txt
Normal file
124
CMakeLists.txt
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
|
||||||
|
project(breeze10)
|
||||||
|
set(PROJECT_VERSION "0.1")
|
||||||
|
set(PROJECT_VERSION_MAJOR 0)
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 2.8.12 FATAL_ERROR)
|
||||||
|
|
||||||
|
include(WriteBasicConfigVersionFile)
|
||||||
|
include(FeatureSummary)
|
||||||
|
|
||||||
|
find_package(ECM 0.0.9 REQUIRED NO_MODULE)
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules")
|
||||||
|
|
||||||
|
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
|
include(ECMInstallIcons)
|
||||||
|
include(KDEInstallDirs)
|
||||||
|
include(KDECMakeSettings)
|
||||||
|
include(KDECompilerSettings NO_POLICY_SCOPE)
|
||||||
|
include(GenerateExportHeader)
|
||||||
|
# include(GtkUpdateIconCache)
|
||||||
|
|
||||||
|
find_package(KDecoration2 REQUIRED)
|
||||||
|
|
||||||
|
|
||||||
|
# old stuff
|
||||||
|
add_definitions(-DTRANSLATION_DOMAIN="breeze_kwin_deco")
|
||||||
|
|
||||||
|
find_package(KF5 REQUIRED COMPONENTS CoreAddons GuiAddons ConfigWidgets WindowSystem I18n)
|
||||||
|
find_package(Qt5 CONFIG REQUIRED COMPONENTS DBus)
|
||||||
|
|
||||||
|
### XCB
|
||||||
|
find_package(XCB COMPONENTS XCB)
|
||||||
|
set_package_properties(XCB PROPERTIES
|
||||||
|
DESCRIPTION "X protocol C-language Binding"
|
||||||
|
URL "http://xcb.freedesktop.org"
|
||||||
|
TYPE OPTIONAL
|
||||||
|
PURPOSE "Required to pass style properties to native Windows on X11 Platform"
|
||||||
|
)
|
||||||
|
|
||||||
|
if(UNIX AND NOT APPLE)
|
||||||
|
|
||||||
|
set(BREEZE_HAVE_X11 ${XCB_XCB_FOUND})
|
||||||
|
if (XCB_XCB_FOUND)
|
||||||
|
find_package(Qt5 REQUIRED CONFIG COMPONENTS X11Extras)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
else()
|
||||||
|
|
||||||
|
set(BREEZE_HAVE_X11 FALSE)
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
|
################# configuration #################
|
||||||
|
configure_file(config-breeze.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-breeze.h )
|
||||||
|
|
||||||
|
################# includes #################
|
||||||
|
add_subdirectory(libbreezecommon)
|
||||||
|
|
||||||
|
################# newt target #################
|
||||||
|
### plugin classes
|
||||||
|
set(breeze10_SRCS
|
||||||
|
breezebutton.cpp
|
||||||
|
breezedecoration.cpp
|
||||||
|
breezeexceptionlist.cpp
|
||||||
|
breezesettingsprovider.cpp
|
||||||
|
breezesizegrip.cpp)
|
||||||
|
|
||||||
|
kconfig_add_kcfg_files(breeze10_SRCS breezesettings.kcfgc)
|
||||||
|
|
||||||
|
### config classes
|
||||||
|
### they are kept separately because they might move in a separate library in the future
|
||||||
|
set(breeze10_config_SRCS
|
||||||
|
config/breezeconfigwidget.cpp
|
||||||
|
config/breezedetectwidget.cpp
|
||||||
|
config/breezeexceptiondialog.cpp
|
||||||
|
config/breezeexceptionlistwidget.cpp
|
||||||
|
config/breezeexceptionmodel.cpp
|
||||||
|
config/breezeitemmodel.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set(breeze10_config_PART_FORMS
|
||||||
|
config/ui/breezeconfigurationui.ui
|
||||||
|
config/ui/breezedetectwidget.ui
|
||||||
|
config/ui/breezeexceptiondialog.ui
|
||||||
|
config/ui/breezeexceptionlistwidget.ui
|
||||||
|
)
|
||||||
|
|
||||||
|
ki18n_wrap_ui(breeze10_config_PART_FORMS_HEADERS ${breeze10_config_PART_FORMS})
|
||||||
|
|
||||||
|
### build library
|
||||||
|
add_library(breeze10 MODULE
|
||||||
|
${breeze10_SRCS}
|
||||||
|
${breeze10_config_SRCS}
|
||||||
|
${breeze10_config_PART_FORMS_HEADERS})
|
||||||
|
|
||||||
|
target_link_libraries(breeze10
|
||||||
|
PUBLIC
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Gui
|
||||||
|
Qt5::DBus
|
||||||
|
PRIVATE
|
||||||
|
breeze10common5
|
||||||
|
KDecoration2::KDecoration
|
||||||
|
KF5::ConfigCore
|
||||||
|
KF5::CoreAddons
|
||||||
|
KF5::ConfigWidgets
|
||||||
|
KF5::GuiAddons
|
||||||
|
KF5::I18n
|
||||||
|
KF5::WindowSystem)
|
||||||
|
|
||||||
|
if(BREEZE_HAVE_X11)
|
||||||
|
target_link_libraries(breeze10
|
||||||
|
PUBLIC
|
||||||
|
Qt5::X11Extras
|
||||||
|
XCB::XCB)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
install(TARGETS breeze10 DESTINATION ${PLUGIN_INSTALL_DIR}/org.kde.kdecoration2)
|
||||||
|
install(FILES config/breeze10config.desktop DESTINATION ${SERVICES_INSTALL_DIR})
|
||||||
|
# install(TARGETS breezedecoration DESTINATION ${PLUGIN_INSTALL_DIR}/org.kde.kdecoration2)
|
||||||
|
# install(FILES config/breezedecorationconfig.desktop DESTINATION ${SERVICES_INSTALL_DIR})
|
3
ChangeLog
Normal file
3
ChangeLog
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
V5.16
|
||||||
|
---------
|
||||||
|
* Initial release.
|
4
Messages.sh
Normal file
4
Messages.sh
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
#!bin/sh
|
||||||
|
$EXTRACTRC `find . -name \*.rc -o -name \*.ui -o -name \*.kcfg` >> rc.cpp
|
||||||
|
$XGETTEXT `find . -name \*.cc -o -name \*.cpp -o -name \*.h` -o $podir/breeze_kwin_deco.pot
|
||||||
|
rm -f rc.cpp
|
5
NEWS
Normal file
5
NEWS
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
Latest version:
|
||||||
|
|
||||||
|
18 Jun 2019, V5.16
|
||||||
|
|
||||||
|
See "ChangeLog" for changes.
|
53
breeze.h
Normal file
53
breeze.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
#ifndef breeze_h
|
||||||
|
#define breeze_h
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 "breezesettings.h"
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
//* convenience typedefs
|
||||||
|
using InternalSettingsPtr = QSharedPointer<InternalSettings>;
|
||||||
|
using InternalSettingsList = QList<InternalSettingsPtr>;
|
||||||
|
using InternalSettingsListIterator = QListIterator<InternalSettingsPtr>;
|
||||||
|
|
||||||
|
//* metrics
|
||||||
|
enum Metrics
|
||||||
|
{
|
||||||
|
|
||||||
|
// shadow dimensions (pixels)
|
||||||
|
Shadow_Overlap = 3,
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//* exception
|
||||||
|
enum ExceptionMask
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
BorderSize = 1<<4
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
16
breeze.json
Normal file
16
breeze.json
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
{
|
||||||
|
"KPlugin": {
|
||||||
|
"Description": "Window decoration using the Breeze visual style for the Plasma Desktop",
|
||||||
|
"EnabledByDefault": true,
|
||||||
|
"Id": "com.github.fauzie811.breeze10",
|
||||||
|
"Name": "Breeze10",
|
||||||
|
"ServiceTypes": [
|
||||||
|
"org.kde.kdecoration2"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"org.kde.kdecoration2": {
|
||||||
|
"blur": true,
|
||||||
|
"defaultTheme": "Breeze10",
|
||||||
|
"kcmodule": true
|
||||||
|
}
|
||||||
|
}
|
531
breezebutton.cpp
Normal file
531
breezebutton.cpp
Normal file
|
@ -0,0 +1,531 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 "breezebutton.h"
|
||||||
|
|
||||||
|
#include <KDecoration2/DecoratedClient>
|
||||||
|
#include <KColorUtils>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
using KDecoration2::ColorRole;
|
||||||
|
using KDecoration2::ColorGroup;
|
||||||
|
using KDecoration2::DecorationButtonType;
|
||||||
|
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
Button::Button(DecorationButtonType type, Decoration* decoration, QObject* parent)
|
||||||
|
: DecorationButton(type, decoration, parent)
|
||||||
|
, m_animation( new QPropertyAnimation( this ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
// setup animation
|
||||||
|
m_animation->setStartValue( 0 );
|
||||||
|
m_animation->setEndValue( 1.0 );
|
||||||
|
m_animation->setTargetObject( this );
|
||||||
|
m_animation->setPropertyName( "opacity" );
|
||||||
|
m_animation->setEasingCurve( QEasingCurve::InOutQuad );
|
||||||
|
|
||||||
|
// setup default geometry
|
||||||
|
const int height = decoration->buttonHeight();
|
||||||
|
const int width = height * (type == DecorationButtonType::Menu ? 1.0 : 1.5);
|
||||||
|
setGeometry(QRect(0, 0, width, height));
|
||||||
|
setIconSize(QSize( width, height ));
|
||||||
|
|
||||||
|
// connections
|
||||||
|
connect(decoration->client().data(), SIGNAL(iconChanged(QIcon)), this, SLOT(update()));
|
||||||
|
connect(decoration->settings().data(), &KDecoration2::DecorationSettings::reconfigured, this, &Button::reconfigure);
|
||||||
|
connect( this, &KDecoration2::DecorationButton::hoveredChanged, this, &Button::updateAnimationState );
|
||||||
|
|
||||||
|
reconfigure();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
Button::Button(QObject *parent, const QVariantList &args)
|
||||||
|
: Button(args.at(0).value<DecorationButtonType>(), args.at(1).value<Decoration*>(), parent)
|
||||||
|
{
|
||||||
|
m_flag = FlagStandalone;
|
||||||
|
//! icon size must return to !valid because it was altered from the default constructor,
|
||||||
|
//! in Standalone mode the button is not using the decoration metrics but its geometry
|
||||||
|
m_iconSize = QSize(-1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
Button *Button::create(DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent)
|
||||||
|
{
|
||||||
|
if (auto d = qobject_cast<Decoration*>(decoration))
|
||||||
|
{
|
||||||
|
Button *b = new Button(type, d, parent);
|
||||||
|
switch( type )
|
||||||
|
{
|
||||||
|
|
||||||
|
case DecorationButtonType::Close:
|
||||||
|
b->setVisible( d->client().data()->isCloseable() );
|
||||||
|
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::closeableChanged, b, &Breeze::Button::setVisible );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationButtonType::Maximize:
|
||||||
|
b->setVisible( d->client().data()->isMaximizeable() );
|
||||||
|
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::maximizeableChanged, b, &Breeze::Button::setVisible );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationButtonType::Minimize:
|
||||||
|
b->setVisible( d->client().data()->isMinimizeable() );
|
||||||
|
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::minimizeableChanged, b, &Breeze::Button::setVisible );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationButtonType::ContextHelp:
|
||||||
|
b->setVisible( d->client().data()->providesContextHelp() );
|
||||||
|
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::providesContextHelpChanged, b, &Breeze::Button::setVisible );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationButtonType::Shade:
|
||||||
|
b->setVisible( d->client().data()->isShadeable() );
|
||||||
|
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::shadeableChanged, b, &Breeze::Button::setVisible );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DecorationButtonType::Menu:
|
||||||
|
QObject::connect(d->client().data(), &KDecoration2::DecoratedClient::iconChanged, b, [b]() { b->update(); });
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
void Button::paint(QPainter *painter, const QRect &repaintRegion)
|
||||||
|
{
|
||||||
|
Q_UNUSED(repaintRegion)
|
||||||
|
|
||||||
|
if (!decoration()) return;
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
// translate from offset
|
||||||
|
if( m_flag == FlagFirstInList ) painter->translate( m_offset );
|
||||||
|
else painter->translate( 0, m_offset.y() );
|
||||||
|
|
||||||
|
if( !m_iconSize.isValid() ) m_iconSize = geometry().size().toSize();
|
||||||
|
|
||||||
|
// menu button
|
||||||
|
if (type() == DecorationButtonType::Menu)
|
||||||
|
{
|
||||||
|
|
||||||
|
// const QRectF iconRect( geometry().topLeft(), m_iconSize );
|
||||||
|
const int menuIconSize = (qobject_cast<Decoration *>(decoration()))->iconSize();
|
||||||
|
const qreal topLeft = (geometry().width()/2) - (menuIconSize/2);
|
||||||
|
|
||||||
|
const QRectF iconRect(topLeft + geometry().left(), topLeft + geometry().top(), menuIconSize, menuIconSize);
|
||||||
|
decoration()->client().data()->icon().paint(painter, iconRect.toRect());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
drawIcon( painter );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
void Button::drawIcon( QPainter *painter ) const
|
||||||
|
{
|
||||||
|
|
||||||
|
painter->setRenderHints( QPainter::Antialiasing );
|
||||||
|
|
||||||
|
/*
|
||||||
|
scale painter so that its window matches QRect( 0, 0, 45, 30 )
|
||||||
|
this makes all further rendering and scaling simpler
|
||||||
|
all further rendering is preformed inside QRect( 0, 0, 45, 30 )
|
||||||
|
*/
|
||||||
|
painter->translate( geometry().topLeft() );
|
||||||
|
|
||||||
|
const qreal height( m_iconSize.height() );
|
||||||
|
const qreal width( m_iconSize.width() );
|
||||||
|
if ( height != 30 )
|
||||||
|
painter->scale( width/45, height/30 );
|
||||||
|
|
||||||
|
// render background
|
||||||
|
const QColor backgroundColor( this->backgroundColor() );
|
||||||
|
|
||||||
|
auto d = qobject_cast<Decoration*>( decoration() );
|
||||||
|
bool isInactive(d && !d->client().data()->isActive()
|
||||||
|
&& !isHovered() && !isPressed()
|
||||||
|
&& m_animation->state() != QPropertyAnimation::Running);
|
||||||
|
QColor inactiveCol(Qt::gray);
|
||||||
|
if (isInactive)
|
||||||
|
{
|
||||||
|
int gray = qGray(d->titleBarColor().rgb());
|
||||||
|
if (gray <= 200) {
|
||||||
|
gray += 55;
|
||||||
|
gray = qMax(gray, 115);
|
||||||
|
}
|
||||||
|
else gray -= 45;
|
||||||
|
inactiveCol = QColor(gray, gray, gray);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render mark
|
||||||
|
const QColor foregroundColor( this->foregroundColor() );
|
||||||
|
if( foregroundColor.isValid() )
|
||||||
|
{
|
||||||
|
|
||||||
|
// setup painter
|
||||||
|
QPen pen( foregroundColor );
|
||||||
|
pen.setCapStyle( Qt::FlatCap );
|
||||||
|
pen.setJoinStyle( Qt::MiterJoin );
|
||||||
|
// pen.setWidthF( 1.0*qMax((qreal)1.0, 30/width ) );
|
||||||
|
pen.setWidthF( 1.0 );
|
||||||
|
|
||||||
|
switch( type() )
|
||||||
|
{
|
||||||
|
|
||||||
|
case DecorationButtonType::Close:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
pen.setWidthF( 1.1 );
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
painter->drawLine( QPointF( 18, 10 ), QPointF( 28, 20 ) );
|
||||||
|
painter->drawLine( QPointF( 18, 20 ), QPointF( 28, 10 ) );
|
||||||
|
pen.setWidthF( 1.0 );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::Maximize:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
if (isChecked())
|
||||||
|
{
|
||||||
|
painter->drawRect(QRectF(18.5, 12.5, 7.0, 7.0));
|
||||||
|
painter->drawPolyline(QPolygonF()
|
||||||
|
<< QPointF(20.5, 12.5) << QPointF(20.5, 10.5) << QPointF(27.5, 10.5) << QPointF(27.5, 17.5) << QPointF(25.5, 17.5));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
painter->drawRect(QRectF(18.5, 10.5, 9.0, 9.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::Minimize:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
painter->drawLine( QPointF( 18, 15.5 ), QPointF( 28, 15.5 ) );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::OnAllDesktops:
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
painter->setBrush( foregroundColor );
|
||||||
|
|
||||||
|
if( isChecked()) {
|
||||||
|
|
||||||
|
// outer ring
|
||||||
|
painter->drawRect( QRectF( 16, 9, 12, 12 ) );
|
||||||
|
|
||||||
|
// center dot
|
||||||
|
QColor backgroundColor( this->backgroundColor() );
|
||||||
|
if( !backgroundColor.isValid() && d ) backgroundColor = d->titleBarColor();
|
||||||
|
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 21, 14, 2, 2 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
painter->drawPolygon( QPolygonF()
|
||||||
|
<< QPointF( 19.5, 14.5 )
|
||||||
|
<< QPointF( 25, 9 )
|
||||||
|
<< QPointF( 28, 12 )
|
||||||
|
<< QPointF( 22.5, 17.5 ) );
|
||||||
|
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->drawLine( QPointF( 18.5, 13.5 ), QPointF( 23.5, 18.5 ) );
|
||||||
|
painter->drawLine( QPointF( 25, 12 ), QPointF( 17.5, 19.5 ) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::Shade:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
painter->drawLine( 18, 12, 26, 12 );
|
||||||
|
if (isChecked()) {
|
||||||
|
painter->drawPolyline( QPolygonF()
|
||||||
|
<< QPointF( 18, 15 )
|
||||||
|
<< QPointF( 22, 19 )
|
||||||
|
<< QPointF( 26, 15 ) );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
painter->drawPolyline( QPolygonF()
|
||||||
|
<< QPointF( 18, 19 )
|
||||||
|
<< QPointF( 22, 15 )
|
||||||
|
<< QPointF( 26, 19 ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::KeepBelow:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
painter->drawPolyline( QPolygonF()
|
||||||
|
<< QPointF( 18, 11 )
|
||||||
|
<< QPointF( 22, 15 )
|
||||||
|
<< QPointF( 26, 11 ) );
|
||||||
|
|
||||||
|
painter->drawPolyline( QPolygonF()
|
||||||
|
<< QPointF( 18, 15 )
|
||||||
|
<< QPointF( 22, 19 )
|
||||||
|
<< QPointF( 26, 15 ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::KeepAbove:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
painter->drawPolyline( QPolygonF()
|
||||||
|
<< QPointF( 18, 15 )
|
||||||
|
<< QPointF( 22, 11 )
|
||||||
|
<< QPointF( 26, 15 ) );
|
||||||
|
|
||||||
|
painter->drawPolyline( QPolygonF()
|
||||||
|
<< QPointF( 18, 19 )
|
||||||
|
<< QPointF( 22, 15 )
|
||||||
|
<< QPointF( 26, 19 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
case DecorationButtonType::ApplicationMenu:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
painter->drawLine( QPointF( 15, 11.5 ), QPointF( 30, 11.5 ) );
|
||||||
|
painter->drawLine( QPointF( 15, 15.5 ), QPointF( 30, 15.5 ) );
|
||||||
|
painter->drawLine( QPointF( 15, 19.5 ), QPointF( 30, 19.5 ) );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case DecorationButtonType::ContextHelp:
|
||||||
|
{
|
||||||
|
if( backgroundColor.isValid() )
|
||||||
|
{
|
||||||
|
painter->setPen( Qt::NoPen );
|
||||||
|
painter->setBrush( backgroundColor );
|
||||||
|
painter->drawRect( QRectF( 0, 0, 45, 30 ) );
|
||||||
|
}
|
||||||
|
painter->setPen( pen );
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
|
||||||
|
QPainterPath path;
|
||||||
|
path.moveTo( 18, 12 );
|
||||||
|
path.arcTo( QRectF( 18, 9.5, 8, 5 ), 180, -180 );
|
||||||
|
path.cubicTo( QPointF(26.5, 15.5), QPointF( 22, 13.5 ), QPointF( 22, 17.5 ) );
|
||||||
|
painter->drawPath( path );
|
||||||
|
|
||||||
|
painter->drawPoint( 22, 21 );
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
QColor Button::foregroundColor() const
|
||||||
|
{
|
||||||
|
auto d = qobject_cast<Decoration*>( decoration() );
|
||||||
|
if( !d ) {
|
||||||
|
|
||||||
|
return QColor();
|
||||||
|
|
||||||
|
} else if( ( type() == DecorationButtonType::KeepBelow || type() == DecorationButtonType::KeepAbove ) && isChecked() ) {
|
||||||
|
|
||||||
|
return d->titleBarColor();
|
||||||
|
|
||||||
|
} else if( m_animation->state() == QPropertyAnimation::Running && type() == DecorationButtonType::Close ) {
|
||||||
|
|
||||||
|
return KColorUtils::mix( d->fontColor(), Qt::white, m_opacity );
|
||||||
|
|
||||||
|
} else if( isHovered() && type() == DecorationButtonType::Close ) {
|
||||||
|
|
||||||
|
return Qt::white;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return d->fontColor();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
QColor Button::backgroundColor() const
|
||||||
|
{
|
||||||
|
auto d = qobject_cast<Decoration*>( decoration() );
|
||||||
|
if( !d ) {
|
||||||
|
|
||||||
|
return QColor();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( isPressed() ) {
|
||||||
|
|
||||||
|
if( type() == DecorationButtonType::Close ) return KColorUtils::mix( Qt::red, Qt::black, 0.3 );
|
||||||
|
else return KColorUtils::mix( d->titleBarColor(), d->fontColor(), 0.3 );
|
||||||
|
|
||||||
|
} else if( ( type() == DecorationButtonType::KeepBelow || type() == DecorationButtonType::KeepAbove ) && isChecked() ) {
|
||||||
|
|
||||||
|
return d->fontColor();
|
||||||
|
|
||||||
|
} else if( m_animation->state() == QPropertyAnimation::Running ) {
|
||||||
|
|
||||||
|
if( type() == DecorationButtonType::Close ) return KColorUtils::mix( d->titleBarColor(), Qt::red, m_opacity );
|
||||||
|
else {
|
||||||
|
|
||||||
|
QColor color( KColorUtils::mix( d->titleBarColor(), d->fontColor(), 0.2 ) );
|
||||||
|
color.setAlpha( color.alpha()*m_opacity );
|
||||||
|
return color;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if( isHovered() ) {
|
||||||
|
|
||||||
|
if( type() == DecorationButtonType::Close ) return Qt::red;
|
||||||
|
else return KColorUtils::mix( d->titleBarColor(), d->fontColor(), 0.2 );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
return QColor();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Button::reconfigure()
|
||||||
|
{
|
||||||
|
|
||||||
|
// animation
|
||||||
|
auto d = qobject_cast<Decoration*>(decoration());
|
||||||
|
if( d ) m_animation->setDuration( d->internalSettings()->animationsDuration() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
void Button::updateAnimationState( bool hovered )
|
||||||
|
{
|
||||||
|
|
||||||
|
auto d = qobject_cast<Decoration*>(decoration());
|
||||||
|
if( !(d && d->internalSettings()->animationsEnabled() ) ) return;
|
||||||
|
|
||||||
|
QAbstractAnimation::Direction dir = hovered ? QPropertyAnimation::Forward : QPropertyAnimation::Backward;
|
||||||
|
if( m_animation->state() == QPropertyAnimation::Running && m_animation->direction() != dir )
|
||||||
|
m_animation->stop();
|
||||||
|
m_animation->setDirection( dir );
|
||||||
|
if( m_animation->state() != QPropertyAnimation::Running ) m_animation->start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
140
breezebutton.h
Normal file
140
breezebutton.h
Normal file
|
@ -0,0 +1,140 @@
|
||||||
|
#ifndef BREEZE_BUTTONS_H
|
||||||
|
#define BREEZE_BUTTONS_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 <KDecoration2/DecorationButton>
|
||||||
|
#include "breezedecoration.h"
|
||||||
|
|
||||||
|
#include <QHash>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
class Button : public KDecoration2::DecorationButton
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
//* declare active state opacity
|
||||||
|
Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity )
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit Button(QObject *parent, const QVariantList &args);
|
||||||
|
|
||||||
|
//* destructor
|
||||||
|
virtual ~Button() = default;
|
||||||
|
|
||||||
|
//* button creation
|
||||||
|
static Button *create(KDecoration2::DecorationButtonType type, KDecoration2::Decoration *decoration, QObject *parent);
|
||||||
|
|
||||||
|
//* render
|
||||||
|
virtual void paint(QPainter *painter, const QRect &repaintRegion) override;
|
||||||
|
|
||||||
|
//* flag
|
||||||
|
enum Flag
|
||||||
|
{
|
||||||
|
FlagNone,
|
||||||
|
FlagStandalone,
|
||||||
|
FlagFirstInList,
|
||||||
|
FlagLastInList
|
||||||
|
};
|
||||||
|
|
||||||
|
//* flag
|
||||||
|
void setFlag( Flag value )
|
||||||
|
{ m_flag = value; }
|
||||||
|
|
||||||
|
//* standalone buttons
|
||||||
|
bool isStandAlone() const { return m_flag == FlagStandalone; }
|
||||||
|
|
||||||
|
//* offset
|
||||||
|
void setOffset( const QPointF& value )
|
||||||
|
{ m_offset = value; }
|
||||||
|
|
||||||
|
//* horizontal offset, for rendering
|
||||||
|
void setHorizontalOffset( qreal value )
|
||||||
|
{ m_offset.setX( value ); }
|
||||||
|
|
||||||
|
//* vertical offset, for rendering
|
||||||
|
void setVerticalOffset( qreal value )
|
||||||
|
{ m_offset.setY( value ); }
|
||||||
|
|
||||||
|
//* set icon size
|
||||||
|
void setIconSize( const QSize& value )
|
||||||
|
{ m_iconSize = value; }
|
||||||
|
|
||||||
|
//*@name active state change animation
|
||||||
|
//@{
|
||||||
|
void setOpacity( qreal value )
|
||||||
|
{
|
||||||
|
if( m_opacity == value ) return;
|
||||||
|
m_opacity = value;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal opacity() const
|
||||||
|
{ return m_opacity; }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
|
||||||
|
//* apply configuration changes
|
||||||
|
void reconfigure();
|
||||||
|
|
||||||
|
//* animation state
|
||||||
|
void updateAnimationState(bool);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* private constructor
|
||||||
|
explicit Button(KDecoration2::DecorationButtonType type, Decoration *decoration, QObject *parent = nullptr);
|
||||||
|
|
||||||
|
//* draw button icon
|
||||||
|
void drawIcon( QPainter *) const;
|
||||||
|
|
||||||
|
//*@name colors
|
||||||
|
//@{
|
||||||
|
QColor foregroundColor() const;
|
||||||
|
QColor backgroundColor() const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
Flag m_flag = FlagNone;
|
||||||
|
|
||||||
|
//* active state change animation
|
||||||
|
QPropertyAnimation *m_animation;
|
||||||
|
|
||||||
|
//* vertical offset (for rendering)
|
||||||
|
QPointF m_offset;
|
||||||
|
|
||||||
|
//* icon size
|
||||||
|
QSize m_iconSize;
|
||||||
|
|
||||||
|
//* active state change opacity
|
||||||
|
qreal m_opacity = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
768
breezedecoration.cpp
Normal file
768
breezedecoration.cpp
Normal file
|
@ -0,0 +1,768 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 "breezedecoration.h"
|
||||||
|
|
||||||
|
#include "breeze.h"
|
||||||
|
#include "breezesettingsprovider.h"
|
||||||
|
#include "config-breeze.h"
|
||||||
|
#include "config/breezeconfigwidget.h"
|
||||||
|
|
||||||
|
#include "breezebutton.h"
|
||||||
|
#include "breezesizegrip.h"
|
||||||
|
|
||||||
|
#include "breezeboxshadowrenderer.h"
|
||||||
|
|
||||||
|
#include <KDecoration2/DecoratedClient>
|
||||||
|
#include <KDecoration2/DecorationButtonGroup>
|
||||||
|
#include <KDecoration2/DecorationSettings>
|
||||||
|
#include <KDecoration2/DecorationShadow>
|
||||||
|
|
||||||
|
#include <KConfigGroup>
|
||||||
|
#include <KColorUtils>
|
||||||
|
#include <KSharedConfig>
|
||||||
|
#include <KPluginFactory>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QTextStream>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
#include <QX11Info>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
K_PLUGIN_FACTORY_WITH_JSON(
|
||||||
|
BreezeDecoFactory,
|
||||||
|
"breeze.json",
|
||||||
|
registerPlugin<Breeze::Decoration>();
|
||||||
|
registerPlugin<Breeze::Button>(QStringLiteral("button"));
|
||||||
|
registerPlugin<Breeze::ConfigWidget>(QStringLiteral("kcmodule"));
|
||||||
|
)
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct ShadowParams {
|
||||||
|
ShadowParams()
|
||||||
|
: offset(QPoint(0, 0))
|
||||||
|
, radius(0)
|
||||||
|
, opacity(0) {}
|
||||||
|
|
||||||
|
ShadowParams(const QPoint &offset, int radius, qreal opacity)
|
||||||
|
: offset(offset)
|
||||||
|
, radius(radius)
|
||||||
|
, opacity(opacity) {}
|
||||||
|
|
||||||
|
QPoint offset;
|
||||||
|
int radius;
|
||||||
|
qreal opacity;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CompositeShadowParams {
|
||||||
|
CompositeShadowParams() = default;
|
||||||
|
|
||||||
|
CompositeShadowParams(
|
||||||
|
const QPoint &offset,
|
||||||
|
const ShadowParams &shadow1,
|
||||||
|
const ShadowParams &shadow2)
|
||||||
|
: offset(offset)
|
||||||
|
, shadow1(shadow1)
|
||||||
|
, shadow2(shadow2) {}
|
||||||
|
|
||||||
|
bool isNone() const {
|
||||||
|
return qMax(shadow1.radius, shadow2.radius) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPoint offset;
|
||||||
|
ShadowParams shadow1;
|
||||||
|
ShadowParams shadow2;
|
||||||
|
};
|
||||||
|
|
||||||
|
const CompositeShadowParams s_shadowParams[] = {
|
||||||
|
// None
|
||||||
|
CompositeShadowParams(),
|
||||||
|
// Small
|
||||||
|
CompositeShadowParams(
|
||||||
|
QPoint(0, 4),
|
||||||
|
ShadowParams(QPoint(0, 0), 16, 1),
|
||||||
|
ShadowParams(QPoint(0, -2), 8, 0.4)),
|
||||||
|
// Medium
|
||||||
|
CompositeShadowParams(
|
||||||
|
QPoint(0, 8),
|
||||||
|
ShadowParams(QPoint(0, 0), 32, 0.9),
|
||||||
|
ShadowParams(QPoint(0, -4), 16, 0.3)),
|
||||||
|
// Large
|
||||||
|
CompositeShadowParams(
|
||||||
|
QPoint(0, 12),
|
||||||
|
ShadowParams(QPoint(0, 0), 48, 0.8),
|
||||||
|
ShadowParams(QPoint(0, -6), 24, 0.2)),
|
||||||
|
// Very large
|
||||||
|
CompositeShadowParams(
|
||||||
|
QPoint(0, 16),
|
||||||
|
ShadowParams(QPoint(0, 0), 64, 0.7),
|
||||||
|
ShadowParams(QPoint(0, -8), 32, 0.1)),
|
||||||
|
};
|
||||||
|
|
||||||
|
inline CompositeShadowParams lookupShadowParams(int size)
|
||||||
|
{
|
||||||
|
switch (size) {
|
||||||
|
case Breeze::InternalSettings::ShadowNone:
|
||||||
|
return s_shadowParams[0];
|
||||||
|
case Breeze::InternalSettings::ShadowSmall:
|
||||||
|
return s_shadowParams[1];
|
||||||
|
case Breeze::InternalSettings::ShadowMedium:
|
||||||
|
return s_shadowParams[2];
|
||||||
|
case Breeze::InternalSettings::ShadowLarge:
|
||||||
|
return s_shadowParams[3];
|
||||||
|
case Breeze::InternalSettings::ShadowVeryLarge:
|
||||||
|
return s_shadowParams[4];
|
||||||
|
default:
|
||||||
|
// Fallback to the Large size.
|
||||||
|
return s_shadowParams[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
using KDecoration2::ColorRole;
|
||||||
|
using KDecoration2::ColorGroup;
|
||||||
|
using KDecoration2::DecorationButtonType;
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
static int g_sDecoCount = 0;
|
||||||
|
static int g_shadowSizeEnum = InternalSettings::ShadowLarge;
|
||||||
|
static int g_shadowStrength = 255;
|
||||||
|
static QColor g_shadowColor = Qt::black;
|
||||||
|
static QSharedPointer<KDecoration2::DecorationShadow> g_sShadow;
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
Decoration::Decoration(QObject *parent, const QVariantList &args)
|
||||||
|
: KDecoration2::Decoration(parent, args)
|
||||||
|
, m_animation( new QPropertyAnimation( this ) )
|
||||||
|
{
|
||||||
|
g_sDecoCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
Decoration::~Decoration()
|
||||||
|
{
|
||||||
|
g_sDecoCount--;
|
||||||
|
if (g_sDecoCount == 0) {
|
||||||
|
// last deco destroyed, clean up shadow
|
||||||
|
g_sShadow.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteSizeGrip();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::setOpacity( qreal value )
|
||||||
|
{
|
||||||
|
if( m_opacity == value ) return;
|
||||||
|
m_opacity = value;
|
||||||
|
update();
|
||||||
|
|
||||||
|
if( m_sizeGrip ) m_sizeGrip->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
QColor Decoration::titleBarColor() const
|
||||||
|
{
|
||||||
|
|
||||||
|
auto c = client().data();
|
||||||
|
if( hideTitleBar() ) return c->color( ColorGroup::Inactive, ColorRole::TitleBar );
|
||||||
|
else if( m_animation->state() == QPropertyAnimation::Running )
|
||||||
|
{
|
||||||
|
return KColorUtils::mix(
|
||||||
|
c->color( ColorGroup::Inactive, ColorRole::TitleBar ),
|
||||||
|
c->color( ColorGroup::Active, ColorRole::TitleBar ),
|
||||||
|
m_opacity );
|
||||||
|
} else return c->color( c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::TitleBar );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
QColor Decoration::fontColor() const
|
||||||
|
{
|
||||||
|
|
||||||
|
auto c = client().data();
|
||||||
|
if( m_animation->state() == QPropertyAnimation::Running )
|
||||||
|
{
|
||||||
|
return KColorUtils::mix(
|
||||||
|
c->color( ColorGroup::Inactive, ColorRole::Foreground ),
|
||||||
|
c->color( ColorGroup::Active, ColorRole::Foreground ),
|
||||||
|
m_opacity );
|
||||||
|
} else return c->color( c->isActive() ? ColorGroup::Active : ColorGroup::Inactive, ColorRole::Foreground );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::init()
|
||||||
|
{
|
||||||
|
auto c = client().data();
|
||||||
|
|
||||||
|
// active state change animation
|
||||||
|
m_animation->setStartValue( 0 );
|
||||||
|
m_animation->setEndValue( 1.0 );
|
||||||
|
m_animation->setTargetObject( this );
|
||||||
|
m_animation->setPropertyName( "opacity" );
|
||||||
|
m_animation->setEasingCurve( QEasingCurve::InOutQuad );
|
||||||
|
|
||||||
|
reconfigure();
|
||||||
|
updateTitleBar();
|
||||||
|
auto s = settings();
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::borderSizeChanged, this, &Decoration::recalculateBorders);
|
||||||
|
|
||||||
|
// a change in font might cause the borders to change
|
||||||
|
recalculateBorders();
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::recalculateBorders);
|
||||||
|
|
||||||
|
// buttons
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::spacingChanged, this, &Decoration::updateButtonsGeometryDelayed);
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsLeftChanged, this, &Decoration::updateButtonsGeometryDelayed);
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::decorationButtonsRightChanged, this, &Decoration::updateButtonsGeometryDelayed);
|
||||||
|
|
||||||
|
// full reconfiguration
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::reconfigure);
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, SettingsProvider::self(), &SettingsProvider::reconfigure, Qt::UniqueConnection );
|
||||||
|
connect(s.data(), &KDecoration2::DecorationSettings::reconfigured, this, &Decoration::updateButtonsGeometryDelayed);
|
||||||
|
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::adjacentScreenEdgesChanged, this, &Decoration::recalculateBorders);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::maximizedHorizontallyChanged, this, &Decoration::recalculateBorders);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::maximizedVerticallyChanged, this, &Decoration::recalculateBorders);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::recalculateBorders);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::captionChanged, this,
|
||||||
|
[this]()
|
||||||
|
{
|
||||||
|
// update the caption area
|
||||||
|
update(titleBar());
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::activeChanged, this, &Decoration::updateAnimationState);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateTitleBar);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateTitleBar);
|
||||||
|
//connect(c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::setOpaque);
|
||||||
|
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::widthChanged, this, &Decoration::updateButtonsGeometry);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateButtonsGeometry);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::adjacentScreenEdgesChanged, this, &Decoration::updateButtonsGeometry);
|
||||||
|
connect(c, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateButtonsGeometry);
|
||||||
|
|
||||||
|
createButtons();
|
||||||
|
createShadow();
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::updateTitleBar()
|
||||||
|
{
|
||||||
|
auto s = settings();
|
||||||
|
auto c = client().data();
|
||||||
|
const bool maximized = isMaximized();
|
||||||
|
const int width = c->width() - (borderSize()*2);
|
||||||
|
const int height = maximized ? borderTop() : borderTop() - borderSize();
|
||||||
|
const int x = borderSize();
|
||||||
|
const int y = maximized ? 0 : borderSize();
|
||||||
|
setTitleBar(QRect(x, y, width, height));
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::updateAnimationState()
|
||||||
|
{
|
||||||
|
if( m_internalSettings->animationsEnabled() )
|
||||||
|
{
|
||||||
|
|
||||||
|
auto c = client().data();
|
||||||
|
m_animation->setDirection( c->isActive() ? QPropertyAnimation::Forward : QPropertyAnimation::Backward );
|
||||||
|
if( m_animation->state() != QPropertyAnimation::Running ) m_animation->start();
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::updateSizeGripVisibility()
|
||||||
|
{
|
||||||
|
auto c = client().data();
|
||||||
|
if( m_sizeGrip )
|
||||||
|
{ m_sizeGrip->setVisible( c->isResizeable() && !isMaximized() && !c->isShaded() ); }
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
int Decoration::borderSize(bool bottom) const
|
||||||
|
{
|
||||||
|
const int baseSize = settings()->smallSpacing();
|
||||||
|
if( m_internalSettings && (m_internalSettings->mask() & BorderSize ) )
|
||||||
|
{
|
||||||
|
switch (m_internalSettings->borderSize()) {
|
||||||
|
case InternalSettings::BorderNone: return 0;
|
||||||
|
case InternalSettings::BorderNoSides: return bottom ? qMax(4, baseSize) : 0;
|
||||||
|
default:
|
||||||
|
case InternalSettings::BorderTiny: return baseSize/2;
|
||||||
|
case InternalSettings::BorderNormal: return baseSize;
|
||||||
|
case InternalSettings::BorderLarge: return baseSize*2;
|
||||||
|
case InternalSettings::BorderVeryLarge: return baseSize*3;
|
||||||
|
case InternalSettings::BorderHuge: return baseSize*4;
|
||||||
|
case InternalSettings::BorderVeryHuge: return baseSize*5;
|
||||||
|
case InternalSettings::BorderOversized: return baseSize*8;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
switch (settings()->borderSize()) {
|
||||||
|
case KDecoration2::BorderSize::None: return 0;
|
||||||
|
case KDecoration2::BorderSize::NoSides: return bottom ? qMax(4, baseSize) : 0;
|
||||||
|
default:
|
||||||
|
case KDecoration2::BorderSize::Tiny: return baseSize/2;
|
||||||
|
case KDecoration2::BorderSize::Normal: return baseSize;
|
||||||
|
case KDecoration2::BorderSize::Large: return baseSize*2;
|
||||||
|
case KDecoration2::BorderSize::VeryLarge: return baseSize*3;
|
||||||
|
case KDecoration2::BorderSize::Huge: return baseSize*4;
|
||||||
|
case KDecoration2::BorderSize::VeryHuge: return baseSize*5;
|
||||||
|
case KDecoration2::BorderSize::Oversized: return baseSize*8;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::reconfigure()
|
||||||
|
{
|
||||||
|
|
||||||
|
m_internalSettings = SettingsProvider::self()->internalSettings( this );
|
||||||
|
|
||||||
|
// animation
|
||||||
|
m_animation->setDuration( m_internalSettings->animationsDuration() );
|
||||||
|
|
||||||
|
// borders
|
||||||
|
recalculateBorders();
|
||||||
|
|
||||||
|
// shadow
|
||||||
|
createShadow();
|
||||||
|
|
||||||
|
// size grip
|
||||||
|
if( hasNoBorders() && m_internalSettings->drawSizeGrip() ) createSizeGrip();
|
||||||
|
else deleteSizeGrip();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::recalculateBorders()
|
||||||
|
{
|
||||||
|
auto c = client().data();
|
||||||
|
auto s = settings();
|
||||||
|
|
||||||
|
// left, right and bottom borders
|
||||||
|
const int left = isLeftEdge() ? 0 : borderSize();
|
||||||
|
const int right = isRightEdge() ? 0 : borderSize();
|
||||||
|
const int bottom = (c->isShaded() || isBottomEdge()) ? 0 : borderSize(true);
|
||||||
|
|
||||||
|
int top = 0;
|
||||||
|
if( hideTitleBar() ) top = bottom;
|
||||||
|
else {
|
||||||
|
top += isMaximized() ? 0 : borderSize();
|
||||||
|
QFont f; f.fromString(m_internalSettings->titleBarFont());
|
||||||
|
QFontMetrics fm(f);
|
||||||
|
top += qMax(fm.height(), buttonHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
|
setBorders(QMargins(left, top, right, bottom));
|
||||||
|
|
||||||
|
// extended sizes
|
||||||
|
const int extSize = s->largeSpacing();
|
||||||
|
int extSides = 0;
|
||||||
|
int extTop = 0;
|
||||||
|
int extBottom = 0;
|
||||||
|
if( hasNoBorders() || borderSize() < 2 )
|
||||||
|
{
|
||||||
|
extSides = extSize;
|
||||||
|
extBottom = extSize;
|
||||||
|
extTop = extSize;
|
||||||
|
} else if( hasNoSideBorders() ) {
|
||||||
|
extSides = extSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
setResizeOnlyBorders(QMargins(extSides, extTop, extSides, extBottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::createButtons()
|
||||||
|
{
|
||||||
|
m_leftButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Left, this, &Button::create);
|
||||||
|
m_rightButtons = new KDecoration2::DecorationButtonGroup(KDecoration2::DecorationButtonGroup::Position::Right, this, &Button::create);
|
||||||
|
updateButtonsGeometry();
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::updateButtonsGeometryDelayed()
|
||||||
|
{ QTimer::singleShot( 0, this, &Decoration::updateButtonsGeometry ); }
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::updateButtonsGeometry()
|
||||||
|
{
|
||||||
|
const auto s = settings();
|
||||||
|
|
||||||
|
// adjust button position
|
||||||
|
const int bHeight = buttonHeight();
|
||||||
|
foreach( const QPointer<KDecoration2::DecorationButton>& button, m_leftButtons->buttons() + m_rightButtons->buttons() )
|
||||||
|
{
|
||||||
|
const int bWidth = buttonHeight() * (button.data()->type() == DecorationButtonType::Menu ? 1.0 : 1.5);
|
||||||
|
button.data()->setGeometry( QRectF( QPoint( 0, 0 ), QSizeF( bWidth, bHeight ) ) );
|
||||||
|
static_cast<Button*>( button.data() )->setIconSize( QSize( bWidth, bHeight ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool maximized = isMaximized();
|
||||||
|
|
||||||
|
// left buttons
|
||||||
|
if( !m_leftButtons->buttons().isEmpty() )
|
||||||
|
{
|
||||||
|
|
||||||
|
m_leftButtons->setSpacing(0);
|
||||||
|
|
||||||
|
m_leftButtons->setPos(QPointF(borderLeft(), maximized ? 0 : borderSize()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// right buttons
|
||||||
|
if( !m_rightButtons->buttons().isEmpty() )
|
||||||
|
{
|
||||||
|
|
||||||
|
m_rightButtons->setSpacing(0);
|
||||||
|
|
||||||
|
// padding
|
||||||
|
m_rightButtons->setPos(QPointF(size().width() - m_rightButtons->geometry().width() - borderRight(), maximized ? 0 : borderSize()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::paint(QPainter *painter, const QRect &repaintRegion)
|
||||||
|
{
|
||||||
|
// TODO: optimize based on repaintRegion
|
||||||
|
auto c = client().data();
|
||||||
|
auto s = settings();
|
||||||
|
|
||||||
|
const bool maximized = isMaximized();
|
||||||
|
|
||||||
|
// paint background
|
||||||
|
if( borderSize() > 0 )
|
||||||
|
{
|
||||||
|
painter->fillRect(rect(), Qt::transparent);
|
||||||
|
painter->save();
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing);
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
|
||||||
|
QColor winCol = c->isActive() ? KColorUtils::mix( titleBarColor(), Qt::black, 0.3 ) : titleBarColor();
|
||||||
|
winCol.setAlpha(titleBarAlpha());
|
||||||
|
painter->setBrush(winCol);
|
||||||
|
|
||||||
|
// clip away the titlebar part
|
||||||
|
if( !hideTitleBar() )
|
||||||
|
{
|
||||||
|
QRegion outerReg(rect());
|
||||||
|
QRegion innerReg(QRect(borderLeft(), maximized ? 0 : borderSize(), size().width() - borderLeft() - borderRight(), buttonHeight()));
|
||||||
|
painter->setClipRegion(outerReg.subtracted(innerReg));
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->drawRect( rect() );
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !hideTitleBar() ) paintTitleBar(painter, repaintRegion);
|
||||||
|
|
||||||
|
if( hasBorders() && !s->isAlphaChannelSupported() )
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
painter->setRenderHint(QPainter::Antialiasing, false);
|
||||||
|
painter->setBrush( Qt::NoBrush );
|
||||||
|
painter->setPen( c->isActive() ?
|
||||||
|
c->color( ColorGroup::Active, ColorRole::TitleBar ):
|
||||||
|
c->color( ColorGroup::Inactive, ColorRole::Foreground ) );
|
||||||
|
|
||||||
|
painter->drawRect( rect().adjusted( 0, 0, -1, -1 ) );
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::paintTitleBar(QPainter *painter, const QRect &repaintRegion)
|
||||||
|
{
|
||||||
|
const auto c = client().data();
|
||||||
|
const bool maximized = isMaximized();
|
||||||
|
const QRect titleRect(QPoint(borderLeft(), maximized ? 0 : borderSize()), QSize(size().width() - borderLeft() - borderRight(), buttonHeight()));
|
||||||
|
|
||||||
|
if ( !titleRect.intersects(repaintRegion) ) return;
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
painter->setPen(Qt::NoPen);
|
||||||
|
|
||||||
|
QColor titleBarColor = this->titleBarColor();
|
||||||
|
titleBarColor.setAlpha(titleBarAlpha());
|
||||||
|
|
||||||
|
painter->setBrush( titleBarColor );
|
||||||
|
|
||||||
|
auto s = settings();
|
||||||
|
painter->drawRect(titleRect);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
|
||||||
|
// draw caption
|
||||||
|
QFont f; f.fromString(m_internalSettings->titleBarFont());
|
||||||
|
// KDE needs this FIXME: Why?
|
||||||
|
QFontDatabase fd; f.setStyleName(fd.styleString(f));
|
||||||
|
painter->setFont(f);
|
||||||
|
painter->setPen( fontColor() );
|
||||||
|
const auto cR = captionRect();
|
||||||
|
const QString caption = painter->fontMetrics().elidedText(c->caption(), Qt::ElideMiddle, cR.first.width());
|
||||||
|
painter->drawText(cR.first, cR.second | Qt::TextSingleLine, caption);
|
||||||
|
|
||||||
|
// draw all buttons
|
||||||
|
m_leftButtons->paint(painter, repaintRegion);
|
||||||
|
m_rightButtons->paint(painter, repaintRegion);
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
int Decoration::buttonHeight() const
|
||||||
|
{
|
||||||
|
const int baseSize = 10; //settings()->gridUnit();
|
||||||
|
switch( m_internalSettings->buttonSize() )
|
||||||
|
{
|
||||||
|
case InternalSettings::ButtonTiny: return baseSize;
|
||||||
|
case InternalSettings::ButtonSmall: return baseSize*2;
|
||||||
|
default:
|
||||||
|
case InternalSettings::ButtonDefault: return baseSize*3;
|
||||||
|
case InternalSettings::ButtonLarge: return baseSize*4;
|
||||||
|
case InternalSettings::ButtonVeryLarge: return baseSize*5;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
int Decoration::iconSize() const
|
||||||
|
{
|
||||||
|
const int baseSize = 16;
|
||||||
|
switch( m_internalSettings->buttonSize() )
|
||||||
|
{
|
||||||
|
case InternalSettings::ButtonTiny: return baseSize/2;
|
||||||
|
case InternalSettings::ButtonSmall: return baseSize;
|
||||||
|
default:
|
||||||
|
case InternalSettings::ButtonDefault: return baseSize;
|
||||||
|
case InternalSettings::ButtonLarge: return baseSize*1.5;
|
||||||
|
case InternalSettings::ButtonVeryLarge: return baseSize*2;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
QPair<QRect,Qt::Alignment> Decoration::captionRect() const
|
||||||
|
{
|
||||||
|
if( hideTitleBar() ) return qMakePair( QRect(), Qt::AlignCenter );
|
||||||
|
else {
|
||||||
|
|
||||||
|
auto c = client().data();
|
||||||
|
int leftOffset = m_leftButtons->buttons().isEmpty() ?
|
||||||
|
4.0*settings()->smallSpacing():
|
||||||
|
m_leftButtons->geometry().x() + m_leftButtons->geometry().width() + 4.0*settings()->smallSpacing();
|
||||||
|
|
||||||
|
if (!m_leftButtons->buttons().isEmpty()
|
||||||
|
&& m_leftButtons->buttons().last().data()->type() == DecorationButtonType::Menu
|
||||||
|
&& m_internalSettings->titleAlignment() == InternalSettings::AlignLeft)
|
||||||
|
{
|
||||||
|
leftOffset -= 4.0 * settings()->smallSpacing();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const int rightOffset = m_rightButtons->buttons().isEmpty() ?
|
||||||
|
4.0*settings()->smallSpacing() :
|
||||||
|
size().width() - m_rightButtons->geometry().x() + 4.0*settings()->smallSpacing();
|
||||||
|
|
||||||
|
const int yOffset = isMaximized() ? 0 : borderSize();
|
||||||
|
const QRect maxRect( leftOffset, yOffset, size().width() - leftOffset - rightOffset, buttonHeight() );
|
||||||
|
|
||||||
|
switch( m_internalSettings->titleAlignment() )
|
||||||
|
{
|
||||||
|
case InternalSettings::AlignLeft:
|
||||||
|
return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignLeft );
|
||||||
|
|
||||||
|
case InternalSettings::AlignRight:
|
||||||
|
return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignRight );
|
||||||
|
|
||||||
|
case InternalSettings::AlignCenter:
|
||||||
|
return qMakePair( maxRect, Qt::AlignCenter );
|
||||||
|
|
||||||
|
default:
|
||||||
|
case InternalSettings::AlignCenterFullWidth:
|
||||||
|
{
|
||||||
|
|
||||||
|
// full caption rect
|
||||||
|
const QRect fullRect = QRect( 0, yOffset, size().width(), buttonHeight() );
|
||||||
|
QFont f; f.fromString(m_internalSettings->titleBarFont());
|
||||||
|
QFontMetrics fm(f);
|
||||||
|
QRect boundingRect( fm.boundingRect( c->caption()) );
|
||||||
|
|
||||||
|
// text bounding rect
|
||||||
|
boundingRect.setTop( yOffset );
|
||||||
|
boundingRect.setHeight( buttonHeight() );
|
||||||
|
boundingRect.moveLeft( ( size().width() - boundingRect.width() )/2 );
|
||||||
|
|
||||||
|
if( boundingRect.left() < leftOffset ) return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignLeft );
|
||||||
|
else if( boundingRect.right() > size().width() - rightOffset ) return qMakePair( maxRect, Qt::AlignVCenter|Qt::AlignRight );
|
||||||
|
else return qMakePair(fullRect, Qt::AlignCenter);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//________________________________________________________________
|
||||||
|
void Decoration::createShadow()
|
||||||
|
{
|
||||||
|
if (!g_sShadow
|
||||||
|
||g_shadowSizeEnum != m_internalSettings->shadowSize()
|
||||||
|
|| g_shadowStrength != m_internalSettings->shadowStrength()
|
||||||
|
|| g_shadowColor != m_internalSettings->shadowColor())
|
||||||
|
{
|
||||||
|
g_shadowSizeEnum = m_internalSettings->shadowSize();
|
||||||
|
g_shadowStrength = m_internalSettings->shadowStrength();
|
||||||
|
g_shadowColor = m_internalSettings->shadowColor();
|
||||||
|
|
||||||
|
const CompositeShadowParams params = lookupShadowParams(g_shadowSizeEnum);
|
||||||
|
if (params.isNone()) {
|
||||||
|
g_sShadow.clear();
|
||||||
|
setShadow(g_sShadow);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto withOpacity = [](const QColor &color, qreal opacity) -> QColor {
|
||||||
|
QColor c(color);
|
||||||
|
c.setAlphaF(opacity);
|
||||||
|
return c;
|
||||||
|
};
|
||||||
|
|
||||||
|
const QSize boxSize = BoxShadowRenderer::calculateMinimumBoxSize(params.shadow1.radius)
|
||||||
|
.expandedTo(BoxShadowRenderer::calculateMinimumBoxSize(params.shadow2.radius));
|
||||||
|
|
||||||
|
BoxShadowRenderer shadowRenderer;
|
||||||
|
shadowRenderer.setBorderRadius(0.5);
|
||||||
|
shadowRenderer.setBoxSize(boxSize);
|
||||||
|
shadowRenderer.setDevicePixelRatio(1.0); // TODO: Create HiDPI shadows?
|
||||||
|
|
||||||
|
const qreal strength = static_cast<qreal>(g_shadowStrength) / 255.0;
|
||||||
|
shadowRenderer.addShadow(params.shadow1.offset, params.shadow1.radius,
|
||||||
|
withOpacity(g_shadowColor, params.shadow1.opacity * strength));
|
||||||
|
shadowRenderer.addShadow(params.shadow2.offset, params.shadow2.radius,
|
||||||
|
withOpacity(g_shadowColor, params.shadow2.opacity * strength));
|
||||||
|
|
||||||
|
QImage shadowTexture = shadowRenderer.render();
|
||||||
|
|
||||||
|
QPainter painter(&shadowTexture);
|
||||||
|
painter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
|
||||||
|
const QRect outerRect = shadowTexture.rect();
|
||||||
|
|
||||||
|
QRect boxRect(QPoint(0, 0), boxSize);
|
||||||
|
boxRect.moveCenter(outerRect.center());
|
||||||
|
|
||||||
|
// Mask out inner rect.
|
||||||
|
const QMargins padding = QMargins(
|
||||||
|
boxRect.left() - outerRect.left() - Metrics::Shadow_Overlap - params.offset.x(),
|
||||||
|
boxRect.top() - outerRect.top() - Metrics::Shadow_Overlap - params.offset.y(),
|
||||||
|
outerRect.right() - boxRect.right() - Metrics::Shadow_Overlap + params.offset.x(),
|
||||||
|
outerRect.bottom() - boxRect.bottom() - Metrics::Shadow_Overlap + params.offset.y());
|
||||||
|
const QRect innerRect = outerRect - padding;
|
||||||
|
|
||||||
|
painter.setPen(Qt::NoPen);
|
||||||
|
painter.setBrush(Qt::black);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_DestinationOut);
|
||||||
|
painter.drawRoundedRect(innerRect, 0.5, 0.5);
|
||||||
|
|
||||||
|
// Draw outline.
|
||||||
|
painter.setPen(withOpacity(g_shadowColor, 0.2 * strength));
|
||||||
|
painter.setBrush(Qt::NoBrush);
|
||||||
|
painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
|
||||||
|
painter.drawRoundedRect(innerRect, -0.5, -0.5);
|
||||||
|
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
g_sShadow = QSharedPointer<KDecoration2::DecorationShadow>::create();
|
||||||
|
g_sShadow->setPadding(padding);
|
||||||
|
g_sShadow->setInnerShadowRect(QRect(outerRect.center(), QSize(1, 1)));
|
||||||
|
g_sShadow->setShadow(shadowTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
setShadow(g_sShadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________________
|
||||||
|
void Decoration::createSizeGrip()
|
||||||
|
{
|
||||||
|
|
||||||
|
// do nothing if size grip already exist
|
||||||
|
if( m_sizeGrip ) return;
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if( !QX11Info::isPlatformX11() ) return;
|
||||||
|
|
||||||
|
// access client
|
||||||
|
auto c = client().data();
|
||||||
|
if( !c ) return;
|
||||||
|
|
||||||
|
if( c->windowId() != 0 )
|
||||||
|
{
|
||||||
|
m_sizeGrip = new SizeGrip( this );
|
||||||
|
connect( c, &KDecoration2::DecoratedClient::maximizedChanged, this, &Decoration::updateSizeGripVisibility );
|
||||||
|
connect( c, &KDecoration2::DecoratedClient::shadedChanged, this, &Decoration::updateSizeGripVisibility );
|
||||||
|
connect( c, &KDecoration2::DecoratedClient::resizeableChanged, this, &Decoration::updateSizeGripVisibility );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________________
|
||||||
|
void Decoration::deleteSizeGrip()
|
||||||
|
{
|
||||||
|
if( m_sizeGrip )
|
||||||
|
{
|
||||||
|
m_sizeGrip->deleteLater();
|
||||||
|
m_sizeGrip = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
|
||||||
|
#include "breezedecoration.moc"
|
221
breezedecoration.h
Normal file
221
breezedecoration.h
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
#ifndef BREEZE_DECORATION_H
|
||||||
|
#define BREEZE_DECORATION_H
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 "breeze.h"
|
||||||
|
#include "breezesettings.h"
|
||||||
|
|
||||||
|
#include <KDecoration2/Decoration>
|
||||||
|
#include <KDecoration2/DecoratedClient>
|
||||||
|
#include <KDecoration2/DecorationSettings>
|
||||||
|
|
||||||
|
#include <QPalette>
|
||||||
|
#include <QPropertyAnimation>
|
||||||
|
#include <QVariant>
|
||||||
|
|
||||||
|
namespace KDecoration2
|
||||||
|
{
|
||||||
|
class DecorationButton;
|
||||||
|
class DecorationButtonGroup;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
class SizeGrip;
|
||||||
|
class Decoration : public KDecoration2::Decoration
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
//* declare active state opacity
|
||||||
|
Q_PROPERTY( qreal opacity READ opacity WRITE setOpacity )
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit Decoration(QObject *parent = nullptr, const QVariantList &args = QVariantList());
|
||||||
|
|
||||||
|
//* destructor
|
||||||
|
virtual ~Decoration();
|
||||||
|
|
||||||
|
//* paint
|
||||||
|
void paint(QPainter *painter, const QRect &repaintRegion) override;
|
||||||
|
|
||||||
|
//* internal settings
|
||||||
|
InternalSettingsPtr internalSettings() const
|
||||||
|
{ return m_internalSettings; }
|
||||||
|
|
||||||
|
//* caption height
|
||||||
|
int captionHeight() const;
|
||||||
|
|
||||||
|
//* button height
|
||||||
|
int buttonHeight() const;
|
||||||
|
|
||||||
|
//* icon size
|
||||||
|
int iconSize() const;
|
||||||
|
|
||||||
|
//*@name active state change animation
|
||||||
|
//@{
|
||||||
|
void setOpacity( qreal );
|
||||||
|
|
||||||
|
qreal opacity() const
|
||||||
|
{ return m_opacity; }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//*@name colors
|
||||||
|
//@{
|
||||||
|
QColor titleBarColor() const;
|
||||||
|
QColor outlineColor() const;
|
||||||
|
QColor fontColor() const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//*@name maximization modes
|
||||||
|
//@{
|
||||||
|
inline bool isMaximized() const;
|
||||||
|
inline bool isMaximizedHorizontally() const;
|
||||||
|
inline bool isMaximizedVertically() const;
|
||||||
|
|
||||||
|
inline bool isLeftEdge() const;
|
||||||
|
inline bool isRightEdge() const;
|
||||||
|
inline bool isTopEdge() const;
|
||||||
|
inline bool isBottomEdge() const;
|
||||||
|
|
||||||
|
inline bool hideTitleBar() const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
void init() override;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void reconfigure();
|
||||||
|
void recalculateBorders();
|
||||||
|
void updateButtonsGeometry();
|
||||||
|
void updateButtonsGeometryDelayed();
|
||||||
|
void updateTitleBar();
|
||||||
|
void updateAnimationState();
|
||||||
|
void updateSizeGripVisibility();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* return the rect in which caption will be drawn
|
||||||
|
QPair<QRect,Qt::Alignment> captionRect() const;
|
||||||
|
|
||||||
|
void createButtons();
|
||||||
|
void paintTitleBar(QPainter *painter, const QRect &repaintRegion);
|
||||||
|
void createShadow();
|
||||||
|
|
||||||
|
//*@name border size
|
||||||
|
//@{
|
||||||
|
int borderSize(bool bottom = false) const;
|
||||||
|
inline bool hasBorders() const;
|
||||||
|
inline bool hasNoBorders() const;
|
||||||
|
inline bool hasNoSideBorders() const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//*@name color customization
|
||||||
|
//@{
|
||||||
|
inline bool opaqueTitleBar() const;
|
||||||
|
inline int titleBarAlpha() const;
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//*@name size grip
|
||||||
|
//@{
|
||||||
|
void createSizeGrip();
|
||||||
|
void deleteSizeGrip();
|
||||||
|
SizeGrip* sizeGrip() const
|
||||||
|
{ return m_sizeGrip; }
|
||||||
|
//@}
|
||||||
|
|
||||||
|
InternalSettingsPtr m_internalSettings;
|
||||||
|
KDecoration2::DecorationButtonGroup *m_leftButtons = nullptr;
|
||||||
|
KDecoration2::DecorationButtonGroup *m_rightButtons = nullptr;
|
||||||
|
|
||||||
|
//* size grip widget
|
||||||
|
SizeGrip *m_sizeGrip = nullptr;
|
||||||
|
|
||||||
|
//* active state change animation
|
||||||
|
QPropertyAnimation *m_animation;
|
||||||
|
|
||||||
|
//* active state change opacity
|
||||||
|
qreal m_opacity = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
bool Decoration::hasBorders() const
|
||||||
|
{
|
||||||
|
if( m_internalSettings && m_internalSettings->mask() & BorderSize ) return m_internalSettings->borderSize() > InternalSettings::BorderNoSides;
|
||||||
|
else return settings()->borderSize() > KDecoration2::BorderSize::NoSides;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Decoration::hasNoBorders() const
|
||||||
|
{
|
||||||
|
if( m_internalSettings && m_internalSettings->mask() & BorderSize ) return m_internalSettings->borderSize() == InternalSettings::BorderNone;
|
||||||
|
else return settings()->borderSize() == KDecoration2::BorderSize::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Decoration::hasNoSideBorders() const
|
||||||
|
{
|
||||||
|
if( m_internalSettings && m_internalSettings->mask() & BorderSize ) return m_internalSettings->borderSize() == InternalSettings::BorderNoSides;
|
||||||
|
else return settings()->borderSize() == KDecoration2::BorderSize::NoSides;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Decoration::isMaximized() const
|
||||||
|
{ return client().data()->isMaximized() && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::isMaximizedHorizontally() const
|
||||||
|
{ return client().data()->isMaximizedHorizontally() && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::isMaximizedVertically() const
|
||||||
|
{ return client().data()->isMaximizedVertically() && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::isLeftEdge() const
|
||||||
|
{ return (client().data()->isMaximizedHorizontally() || client().data()->adjacentScreenEdges().testFlag( Qt::LeftEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::isRightEdge() const
|
||||||
|
{ return (client().data()->isMaximizedHorizontally() || client().data()->adjacentScreenEdges().testFlag( Qt::RightEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::isTopEdge() const
|
||||||
|
{ return (client().data()->isMaximizedVertically() || client().data()->adjacentScreenEdges().testFlag( Qt::TopEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::isBottomEdge() const
|
||||||
|
{ return (client().data()->isMaximizedVertically() || client().data()->adjacentScreenEdges().testFlag( Qt::BottomEdge ) ) && !m_internalSettings->drawBorderOnMaximizedWindows(); }
|
||||||
|
|
||||||
|
bool Decoration::hideTitleBar() const
|
||||||
|
{ return m_internalSettings->hideTitleBar() && !client().data()->isShaded(); }
|
||||||
|
|
||||||
|
bool Decoration::opaqueTitleBar() const
|
||||||
|
{ return m_internalSettings->opaqueTitleBar(); }
|
||||||
|
|
||||||
|
int Decoration::titleBarAlpha() const
|
||||||
|
{
|
||||||
|
if (m_internalSettings->opaqueTitleBar())
|
||||||
|
return 255;
|
||||||
|
int a = m_internalSettings->opacityOverride() > -1 ? m_internalSettings->opacityOverride()
|
||||||
|
: m_internalSettings->backgroundOpacity();
|
||||||
|
a = qBound(0, a, 100);
|
||||||
|
return qRound(static_cast<qreal>(a) * static_cast<qreal>(2.55));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
131
breezeexceptionlist.cpp
Normal file
131
breezeexceptionlist.cpp
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptionlist.cpp
|
||||||
|
// window decoration exceptions
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeexceptionlist.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//______________________________________________________________
|
||||||
|
void ExceptionList::readConfig( KSharedConfig::Ptr config )
|
||||||
|
{
|
||||||
|
|
||||||
|
_exceptions.clear();
|
||||||
|
|
||||||
|
QString groupName;
|
||||||
|
for( int index = 0; config->hasGroup( groupName = exceptionGroupName( index ) ); ++index )
|
||||||
|
{
|
||||||
|
|
||||||
|
// create exception
|
||||||
|
InternalSettings exception;
|
||||||
|
|
||||||
|
// reset group
|
||||||
|
readConfig( &exception, config.data(), groupName );
|
||||||
|
|
||||||
|
// create new configuration
|
||||||
|
InternalSettingsPtr configuration( new InternalSettings() );
|
||||||
|
configuration.data()->load();
|
||||||
|
|
||||||
|
// apply changes from exception
|
||||||
|
configuration->setEnabled( exception.enabled() );
|
||||||
|
configuration->setExceptionType( exception.exceptionType() );
|
||||||
|
configuration->setExceptionPattern( exception.exceptionPattern() );
|
||||||
|
configuration->setMask( exception.mask() );
|
||||||
|
|
||||||
|
// propagate all features found in mask to the output configuration
|
||||||
|
if( exception.mask() & BorderSize ) configuration->setBorderSize( exception.borderSize() );
|
||||||
|
configuration->setHideTitleBar( exception.hideTitleBar() );
|
||||||
|
configuration->setOpaqueTitleBar( exception.opaqueTitleBar() );
|
||||||
|
configuration->setOpacityOverride( exception.opacityOverride() );
|
||||||
|
configuration->setIsDialog( exception.isDialog() );
|
||||||
|
|
||||||
|
// append to exceptions
|
||||||
|
_exceptions.append( configuration );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//______________________________________________________________
|
||||||
|
void ExceptionList::writeConfig( KSharedConfig::Ptr config )
|
||||||
|
{
|
||||||
|
|
||||||
|
// remove all existing exceptions
|
||||||
|
QString groupName;
|
||||||
|
for( int index = 0; config->hasGroup( groupName = exceptionGroupName( index ) ); ++index )
|
||||||
|
{ config->deleteGroup( groupName ); }
|
||||||
|
|
||||||
|
// rewrite current exceptions
|
||||||
|
int index = 0;
|
||||||
|
foreach( const InternalSettingsPtr& exception, _exceptions )
|
||||||
|
{
|
||||||
|
|
||||||
|
writeConfig( exception.data(), config.data(), exceptionGroupName( index ) );
|
||||||
|
++index;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________________________
|
||||||
|
QString ExceptionList::exceptionGroupName( int index )
|
||||||
|
{ return QString( "Windeco Exception %1" ).arg( index ); }
|
||||||
|
|
||||||
|
//______________________________________________________________
|
||||||
|
void ExceptionList::writeConfig( KCoreConfigSkeleton* skeleton, KConfig* config, const QString& groupName )
|
||||||
|
{
|
||||||
|
|
||||||
|
// list of items to be written
|
||||||
|
QStringList keys = { "Enabled", "ExceptionPattern", "ExceptionType", "HideTitleBar", "IsDialog", "OpaqueTitleBar", "OpacityOverride", "Mask", "BorderSize"};
|
||||||
|
|
||||||
|
// write all items
|
||||||
|
foreach( auto key, keys )
|
||||||
|
{
|
||||||
|
KConfigSkeletonItem* item( skeleton->findItem( key ) );
|
||||||
|
if( !item ) continue;
|
||||||
|
|
||||||
|
if( !groupName.isEmpty() ) item->setGroup( groupName );
|
||||||
|
KConfigGroup configGroup( config, item->group() );
|
||||||
|
configGroup.writeEntry( item->key(), item->property() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//______________________________________________________________
|
||||||
|
void ExceptionList::readConfig( KCoreConfigSkeleton* skeleton, KConfig* config, const QString& groupName )
|
||||||
|
{
|
||||||
|
|
||||||
|
foreach( KConfigSkeletonItem* item, skeleton->items() )
|
||||||
|
{
|
||||||
|
if( !groupName.isEmpty() ) item->setGroup( groupName );
|
||||||
|
item->readConfig( config );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
79
breezeexceptionlist.h
Normal file
79
breezeexceptionlist.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef breezeexceptionlist_h
|
||||||
|
#define breezeexceptionlist_h
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptionlist.h
|
||||||
|
// window decoration exceptions
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezesettings.h"
|
||||||
|
#include "breeze.h"
|
||||||
|
|
||||||
|
#include <KSharedConfig>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//! breeze exceptions list
|
||||||
|
class ExceptionList
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! constructor from list
|
||||||
|
explicit ExceptionList( const InternalSettingsList& exceptions = InternalSettingsList() ):
|
||||||
|
_exceptions( exceptions )
|
||||||
|
{}
|
||||||
|
|
||||||
|
//! exceptions
|
||||||
|
const InternalSettingsList& get( void ) const
|
||||||
|
{ return _exceptions; }
|
||||||
|
|
||||||
|
//! read from KConfig
|
||||||
|
void readConfig( KSharedConfig::Ptr );
|
||||||
|
|
||||||
|
//! write to kconfig
|
||||||
|
void writeConfig( KSharedConfig::Ptr );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//! generate exception group name for given exception index
|
||||||
|
static QString exceptionGroupName( int index );
|
||||||
|
|
||||||
|
//! read configuration
|
||||||
|
static void readConfig( KCoreConfigSkeleton*, KConfig*, const QString& );
|
||||||
|
|
||||||
|
//! write configuration
|
||||||
|
static void writeConfig( KCoreConfigSkeleton*, KConfig*, const QString& );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! exceptions
|
||||||
|
InternalSettingsList _exceptions;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
6
breezesettings.kcfgc
Normal file
6
breezesettings.kcfgc
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
File=breezesettingsdata.kcfg
|
||||||
|
ClassName=InternalSettings
|
||||||
|
NameSpace=Breeze
|
||||||
|
Singleton=false
|
||||||
|
Mutators=true
|
||||||
|
GlobalEnums=true
|
152
breezesettingsdata.kcfg
Normal file
152
breezesettingsdata.kcfg
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE kcfg SYSTEM "http://www.kde.org/standards/kcfg/1.0/kcfg.dtd">
|
||||||
|
<kcfg>
|
||||||
|
<kcfgfile name="breezerc"/>
|
||||||
|
|
||||||
|
<!-- common options -->
|
||||||
|
<group name="Common">
|
||||||
|
|
||||||
|
<entry name="ShadowStrength" type = "Int">
|
||||||
|
<default>255</default>
|
||||||
|
<min>25</min>
|
||||||
|
<max>255</max>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- shadow -->
|
||||||
|
<entry name="ShadowSize" type = "Enum">
|
||||||
|
<choices>
|
||||||
|
<choice name="ShadowNone"/>
|
||||||
|
<choice name="ShadowSmall"/>
|
||||||
|
<choice name="ShadowMedium"/>
|
||||||
|
<choice name="ShadowLarge"/>
|
||||||
|
<choice name="ShadowVeryLarge"/>
|
||||||
|
</choices>
|
||||||
|
<default>ShadowLarge</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="ShadowColor" type = "Color">
|
||||||
|
<default>0, 0, 0</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- close button -->
|
||||||
|
<entry name="OutlineCloseButton" type = "Bool">
|
||||||
|
<default>true</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
<group name="Windeco">
|
||||||
|
|
||||||
|
<!-- border size -->
|
||||||
|
<!--
|
||||||
|
this one is used only for window specific settings, since the default is globally set by kwin
|
||||||
|
the enumeration must be kept in sync with kwin's global settings
|
||||||
|
-->
|
||||||
|
<entry name="BorderSize" type = "Enum">
|
||||||
|
<choices>
|
||||||
|
<choice name="BorderNone" />
|
||||||
|
<choice name="BorderNoSides" />
|
||||||
|
<choice name="BorderTiny" />
|
||||||
|
<choice name="BorderNormal" />
|
||||||
|
<choice name="BorderLarge" />
|
||||||
|
<choice name="BorderVeryLarge" />
|
||||||
|
<choice name="BorderHuge" />
|
||||||
|
<choice name="BorderVeryHuge" />
|
||||||
|
<choice name="BorderOversized" />
|
||||||
|
</choices>
|
||||||
|
<default>BorderNoSides</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- title alignment -->
|
||||||
|
<entry name="TitleAlignment" type="Enum">
|
||||||
|
<choices>
|
||||||
|
<choice name="AlignLeft" />
|
||||||
|
<choice name="AlignCenter" />
|
||||||
|
<choice name="AlignCenterFullWidth" />
|
||||||
|
<choice name="AlignRight" />
|
||||||
|
</choices>
|
||||||
|
<default>AlignCenterFullWidth</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- button size -->
|
||||||
|
<entry name="ButtonSize" type="Enum">
|
||||||
|
<choices>
|
||||||
|
<choice name="ButtonTiny" />
|
||||||
|
<choice name="ButtonSmall" />
|
||||||
|
<choice name="ButtonDefault" />
|
||||||
|
<choice name="ButtonLarge" />
|
||||||
|
<choice name="ButtonVeryLarge" />
|
||||||
|
</choices>
|
||||||
|
<default>ButtonDefault</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- maximized windows -->
|
||||||
|
<entry name="DrawBorderOnMaximizedWindows" type = "Bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="DrawTitleBarSeparator" type = "Bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="BackgroundOpacity" type = "Int">
|
||||||
|
<default>100</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="TitleBarFont" type = "String"/>
|
||||||
|
|
||||||
|
<!-- size grip -->
|
||||||
|
<entry name="DrawSizeGrip" type = "Bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- animations -->
|
||||||
|
<entry name="AnimationsEnabled" type = "Bool">
|
||||||
|
<default>true</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="AnimationsDuration" type = "Int">
|
||||||
|
<default>150</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- hide title bar -->
|
||||||
|
<entry name="HideTitleBar" type = "Bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- opaque title bar -->
|
||||||
|
<entry name="OpaqueTitleBar" type = "Bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="OpacityOverride" type = "Int">
|
||||||
|
<default>-1</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- dialogs -->
|
||||||
|
<entry name="IsDialog" type = "Bool">
|
||||||
|
<default>false</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<!-- window specific settings -->
|
||||||
|
<entry name="ExceptionType" type="Enum">
|
||||||
|
<choices>
|
||||||
|
<choice name="ExceptionWindowClassName" />
|
||||||
|
<choice name="ExceptionWindowTitle" />
|
||||||
|
</choices>
|
||||||
|
<default>ExceptionWindowClassName</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="ExceptionPattern" type = "String"/>
|
||||||
|
|
||||||
|
<entry name="Enabled" type = "Bool">
|
||||||
|
<default>true</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
<entry name="Mask" type = "Int">
|
||||||
|
<default>0</default>
|
||||||
|
</entry>
|
||||||
|
|
||||||
|
</group>
|
||||||
|
|
||||||
|
</kcfg>
|
139
breezesettingsprovider.cpp
Normal file
139
breezesettingsprovider.cpp
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 "breezesettingsprovider.h"
|
||||||
|
|
||||||
|
#include "breezeexceptionlist.h"
|
||||||
|
|
||||||
|
#include <KWindowInfo>
|
||||||
|
|
||||||
|
#include <QTextStream>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
SettingsProvider *SettingsProvider::s_self = nullptr;
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
SettingsProvider::SettingsProvider():
|
||||||
|
m_config( KSharedConfig::openConfig( QStringLiteral("breezerc") ) )
|
||||||
|
{ reconfigure(); }
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
SettingsProvider::~SettingsProvider()
|
||||||
|
{ s_self = nullptr; }
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
SettingsProvider *SettingsProvider::self()
|
||||||
|
{
|
||||||
|
// TODO: this is not thread safe!
|
||||||
|
if (!s_self)
|
||||||
|
{ s_self = new SettingsProvider(); }
|
||||||
|
|
||||||
|
return s_self;
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
void SettingsProvider::reconfigure()
|
||||||
|
{
|
||||||
|
if( !m_defaultSettings )
|
||||||
|
{
|
||||||
|
m_defaultSettings = InternalSettingsPtr(new InternalSettings());
|
||||||
|
m_defaultSettings->setCurrentGroup( QStringLiteral("Windeco") );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_defaultSettings->load();
|
||||||
|
|
||||||
|
ExceptionList exceptions;
|
||||||
|
exceptions.readConfig( m_config );
|
||||||
|
m_exceptions = exceptions.get();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
InternalSettingsPtr SettingsProvider::internalSettings( Decoration *decoration ) const
|
||||||
|
{
|
||||||
|
|
||||||
|
QString windowTitle;
|
||||||
|
QString className;
|
||||||
|
|
||||||
|
// get the client
|
||||||
|
auto client = decoration->client().data();
|
||||||
|
|
||||||
|
foreach( auto internalSettings, m_exceptions )
|
||||||
|
{
|
||||||
|
|
||||||
|
// discard disabled exceptions
|
||||||
|
if( !internalSettings->enabled() ) continue;
|
||||||
|
|
||||||
|
// discard exceptions with empty exception pattern
|
||||||
|
if( internalSettings->exceptionPattern().isEmpty() ) continue;
|
||||||
|
|
||||||
|
if (internalSettings->isDialog())
|
||||||
|
{
|
||||||
|
KWindowInfo info(client->windowId(), NET::WMWindowType);
|
||||||
|
if (info.valid()
|
||||||
|
&& info.windowType(NET::NormalMask | NET::DialogMask) != NET::Dialog) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
decide which value is to be compared
|
||||||
|
to the regular expression, based on exception type
|
||||||
|
*/
|
||||||
|
QString value;
|
||||||
|
switch( internalSettings->exceptionType() )
|
||||||
|
{
|
||||||
|
case InternalSettings::ExceptionWindowTitle:
|
||||||
|
{
|
||||||
|
value = windowTitle.isEmpty() ? (windowTitle = client->caption()):windowTitle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
case InternalSettings::ExceptionWindowClassName:
|
||||||
|
{
|
||||||
|
if( className.isEmpty() )
|
||||||
|
{
|
||||||
|
// retrieve class name
|
||||||
|
KWindowInfo info( client->windowId(), nullptr, NET::WM2WindowClass );
|
||||||
|
QString window_className( QString::fromUtf8(info.windowClassName()) );
|
||||||
|
QString window_class( QString::fromUtf8(info.windowClassClass()) );
|
||||||
|
className = window_className + QStringLiteral(" ") + window_class;
|
||||||
|
}
|
||||||
|
|
||||||
|
value = className;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// check matching
|
||||||
|
if( QRegExp( internalSettings->exceptionPattern() ).indexIn( value ) >= 0 )
|
||||||
|
{ return internalSettings; }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_defaultSettings;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
76
breezesettingsprovider.h
Normal file
76
breezesettingsprovider.h
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
#ifndef breezesettingsprovider_h
|
||||||
|
#define breezesettingsprovider_h
|
||||||
|
/*
|
||||||
|
* Copyright 2014 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
*
|
||||||
|
* 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) version 3 or any later version
|
||||||
|
* accepted by the membership of KDE e.V. (or its successor approved
|
||||||
|
* by the membership of KDE e.V.), which shall act as a proxy
|
||||||
|
* defined in Section 14 of version 3 of the license.
|
||||||
|
*
|
||||||
|
* 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 "breezedecoration.h"
|
||||||
|
#include "breezesettings.h"
|
||||||
|
#include "breeze.h"
|
||||||
|
|
||||||
|
#include <KSharedConfig>
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
class SettingsProvider: public QObject
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* destructor
|
||||||
|
~SettingsProvider();
|
||||||
|
|
||||||
|
//* singleton
|
||||||
|
static SettingsProvider *self();
|
||||||
|
|
||||||
|
//* internal settings for given decoration
|
||||||
|
InternalSettingsPtr internalSettings(Decoration *) const;
|
||||||
|
|
||||||
|
public Q_SLOTS:
|
||||||
|
|
||||||
|
//* reconfigure
|
||||||
|
void reconfigure();
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* contructor
|
||||||
|
SettingsProvider();
|
||||||
|
|
||||||
|
//* default configuration
|
||||||
|
InternalSettingsPtr m_defaultSettings;
|
||||||
|
|
||||||
|
//* exceptions
|
||||||
|
InternalSettingsList m_exceptions;
|
||||||
|
|
||||||
|
//* config object
|
||||||
|
KSharedConfigPtr m_config;
|
||||||
|
|
||||||
|
//* singleton
|
||||||
|
static SettingsProvider *s_self;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
303
breezesizegrip.cpp
Normal file
303
breezesizegrip.cpp
Normal file
|
@ -0,0 +1,303 @@
|
||||||
|
/*************************************************************************
|
||||||
|
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
|
||||||
|
#include "breezesizegrip.h"
|
||||||
|
|
||||||
|
#include <KDecoration2/DecoratedClient>
|
||||||
|
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPolygon>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
#include <QX11Info>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//* scoped pointer convenience typedef
|
||||||
|
template <typename T> using ScopedPointer = QScopedPointer<T, QScopedPointerPodDeleter>;
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
SizeGrip::SizeGrip( Decoration* decoration ):QWidget(nullptr)
|
||||||
|
,m_decoration( decoration )
|
||||||
|
{
|
||||||
|
|
||||||
|
setAttribute(Qt::WA_NoSystemBackground );
|
||||||
|
setAutoFillBackground( false );
|
||||||
|
|
||||||
|
// cursor
|
||||||
|
setCursor( Qt::SizeFDiagCursor );
|
||||||
|
|
||||||
|
// size
|
||||||
|
setFixedSize( QSize( GripSize, GripSize ) );
|
||||||
|
|
||||||
|
// mask
|
||||||
|
setMask( QRegion( QVector<QPoint>{
|
||||||
|
QPoint( 0, GripSize ),
|
||||||
|
QPoint( GripSize, 0 ),
|
||||||
|
QPoint( GripSize, GripSize ),
|
||||||
|
QPoint( 0, GripSize )} ) );
|
||||||
|
|
||||||
|
// embed
|
||||||
|
embed();
|
||||||
|
updatePosition();
|
||||||
|
|
||||||
|
// connections
|
||||||
|
auto c = decoration->client().data();
|
||||||
|
connect( c, &KDecoration2::DecoratedClient::widthChanged, this, &SizeGrip::updatePosition );
|
||||||
|
connect( c, &KDecoration2::DecoratedClient::heightChanged, this, &SizeGrip::updatePosition );
|
||||||
|
connect( c, &KDecoration2::DecoratedClient::activeChanged, this, &SizeGrip::updateActiveState );
|
||||||
|
|
||||||
|
// show
|
||||||
|
show();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
SizeGrip::~SizeGrip()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
void SizeGrip::updateActiveState()
|
||||||
|
{
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if( QX11Info::isPlatformX11() )
|
||||||
|
{
|
||||||
|
const quint32 value = XCB_STACK_MODE_ABOVE;
|
||||||
|
xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_STACK_MODE, &value );
|
||||||
|
xcb_map_window( QX11Info::connection(), winId() );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
update();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
void SizeGrip::embed()
|
||||||
|
{
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
|
||||||
|
if( !QX11Info::isPlatformX11() ) return;
|
||||||
|
auto c = m_decoration.data()->client().data();
|
||||||
|
|
||||||
|
xcb_window_t windowId = c->windowId();
|
||||||
|
if( windowId )
|
||||||
|
{
|
||||||
|
|
||||||
|
/*
|
||||||
|
find client's parent
|
||||||
|
we want the size grip to be at the same level as the client in the stack
|
||||||
|
*/
|
||||||
|
xcb_window_t current = windowId;
|
||||||
|
auto connection = QX11Info::connection();
|
||||||
|
xcb_query_tree_cookie_t cookie = xcb_query_tree_unchecked( connection, current );
|
||||||
|
ScopedPointer<xcb_query_tree_reply_t> tree(xcb_query_tree_reply( connection, cookie, nullptr ) );
|
||||||
|
if( !tree.isNull() && tree->parent ) current = tree->parent;
|
||||||
|
|
||||||
|
// reparent
|
||||||
|
xcb_reparent_window( connection, winId(), current, 0, 0 );
|
||||||
|
setWindowTitle( "Breeze::SizeGrip" );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
hide();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
void SizeGrip::paintEvent( QPaintEvent* )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( !m_decoration ) return;
|
||||||
|
|
||||||
|
// get relevant colors
|
||||||
|
const QColor backgroundColor( m_decoration.data()->titleBarColor() );
|
||||||
|
|
||||||
|
// create and configure painter
|
||||||
|
QPainter painter(this);
|
||||||
|
painter.setRenderHints(QPainter::Antialiasing );
|
||||||
|
|
||||||
|
painter.setPen( Qt::NoPen );
|
||||||
|
painter.setBrush( backgroundColor );
|
||||||
|
|
||||||
|
// polygon
|
||||||
|
painter.drawPolygon( QVector<QPoint> {
|
||||||
|
QPoint( 0, GripSize ),
|
||||||
|
QPoint( GripSize, 0 ),
|
||||||
|
QPoint( GripSize, GripSize ),
|
||||||
|
QPoint( 0, GripSize )} );
|
||||||
|
}
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
void SizeGrip::mousePressEvent( QMouseEvent* event )
|
||||||
|
{
|
||||||
|
|
||||||
|
switch (event->button())
|
||||||
|
{
|
||||||
|
|
||||||
|
case Qt::RightButton:
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
QTimer::singleShot(5000, this, SLOT(show()));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Qt::MidButton:
|
||||||
|
{
|
||||||
|
hide();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case Qt::LeftButton:
|
||||||
|
if( rect().contains( event->pos() ) )
|
||||||
|
{ sendMoveResizeEvent( event->pos() ); }
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________________________________
|
||||||
|
void SizeGrip::updatePosition()
|
||||||
|
{
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if( !QX11Info::isPlatformX11() ) return;
|
||||||
|
|
||||||
|
auto c = m_decoration.data()->client().data();
|
||||||
|
QPoint position(
|
||||||
|
c->width() - GripSize - Offset,
|
||||||
|
c->height() - GripSize - Offset );
|
||||||
|
|
||||||
|
quint32 values[2] = { quint32(position.x()), quint32(position.y()) };
|
||||||
|
xcb_configure_window( QX11Info::connection(), winId(), XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, values );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
void SizeGrip::sendMoveResizeEvent( QPoint position )
|
||||||
|
{
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if( !QX11Info::isPlatformX11() ) return;
|
||||||
|
|
||||||
|
// pointer to connection
|
||||||
|
auto connection( QX11Info::connection() );
|
||||||
|
|
||||||
|
// client
|
||||||
|
auto c = m_decoration.data()->client().data();
|
||||||
|
|
||||||
|
/*
|
||||||
|
get root position matching position
|
||||||
|
need to use xcb because the embedding of the widget
|
||||||
|
breaks QT's mapToGlobal and other methods
|
||||||
|
*/
|
||||||
|
QPoint rootPosition( position );
|
||||||
|
xcb_get_geometry_cookie_t cookie( xcb_get_geometry( connection, winId() ) );
|
||||||
|
ScopedPointer<xcb_get_geometry_reply_t> reply( xcb_get_geometry_reply( connection, cookie, nullptr ) );
|
||||||
|
if( reply )
|
||||||
|
{
|
||||||
|
|
||||||
|
// translate coordinates
|
||||||
|
xcb_translate_coordinates_cookie_t coordCookie( xcb_translate_coordinates(
|
||||||
|
connection, winId(), reply.data()->root,
|
||||||
|
-reply.data()->border_width,
|
||||||
|
-reply.data()->border_width ) );
|
||||||
|
|
||||||
|
ScopedPointer< xcb_translate_coordinates_reply_t> coordReply( xcb_translate_coordinates_reply( connection, coordCookie, nullptr ) );
|
||||||
|
|
||||||
|
if( coordReply )
|
||||||
|
{
|
||||||
|
rootPosition.rx() += coordReply.data()->dst_x;
|
||||||
|
rootPosition.ry() += coordReply.data()->dst_y;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// move/resize atom
|
||||||
|
if( !m_moveResizeAtom )
|
||||||
|
{
|
||||||
|
|
||||||
|
// create atom if not found
|
||||||
|
const QString atomName( "_NET_WM_MOVERESIZE" );
|
||||||
|
xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) );
|
||||||
|
ScopedPointer<xcb_intern_atom_reply_t> reply( xcb_intern_atom_reply( connection, cookie, nullptr ) );
|
||||||
|
m_moveResizeAtom = reply ? reply->atom:0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if( !m_moveResizeAtom ) return;
|
||||||
|
|
||||||
|
// button release event
|
||||||
|
xcb_button_release_event_t releaseEvent;
|
||||||
|
memset(&releaseEvent, 0, sizeof(releaseEvent));
|
||||||
|
|
||||||
|
releaseEvent.response_type = XCB_BUTTON_RELEASE;
|
||||||
|
releaseEvent.event = winId();
|
||||||
|
releaseEvent.child = XCB_WINDOW_NONE;
|
||||||
|
releaseEvent.root = QX11Info::appRootWindow();
|
||||||
|
releaseEvent.event_x = position.x();
|
||||||
|
releaseEvent.event_y = position.y();
|
||||||
|
releaseEvent.root_x = rootPosition.x();
|
||||||
|
releaseEvent.root_y = rootPosition.y();
|
||||||
|
releaseEvent.detail = XCB_BUTTON_INDEX_1;
|
||||||
|
releaseEvent.state = XCB_BUTTON_MASK_1;
|
||||||
|
releaseEvent.time = XCB_CURRENT_TIME;
|
||||||
|
releaseEvent.same_screen = true;
|
||||||
|
xcb_send_event( connection, false, winId(), XCB_EVENT_MASK_BUTTON_RELEASE, reinterpret_cast<const char*>(&releaseEvent));
|
||||||
|
|
||||||
|
xcb_ungrab_pointer( connection, XCB_TIME_CURRENT_TIME );
|
||||||
|
|
||||||
|
// move resize event
|
||||||
|
xcb_client_message_event_t clientMessageEvent;
|
||||||
|
memset(&clientMessageEvent, 0, sizeof(clientMessageEvent));
|
||||||
|
|
||||||
|
clientMessageEvent.response_type = XCB_CLIENT_MESSAGE;
|
||||||
|
clientMessageEvent.type = m_moveResizeAtom;
|
||||||
|
clientMessageEvent.format = 32;
|
||||||
|
clientMessageEvent.window = c->windowId();
|
||||||
|
clientMessageEvent.data.data32[0] = rootPosition.x();
|
||||||
|
clientMessageEvent.data.data32[1] = rootPosition.y();
|
||||||
|
clientMessageEvent.data.data32[2] = 4; // bottom right
|
||||||
|
clientMessageEvent.data.data32[3] = Qt::LeftButton;
|
||||||
|
clientMessageEvent.data.data32[4] = 0;
|
||||||
|
|
||||||
|
xcb_send_event( connection, false, QX11Info::appRootWindow(),
|
||||||
|
XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
|
||||||
|
XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT,
|
||||||
|
reinterpret_cast<const char*>(&clientMessageEvent) );
|
||||||
|
|
||||||
|
xcb_flush( connection );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
100
breezesizegrip.h
Normal file
100
breezesizegrip.h
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
#ifndef breezesizegrip_h
|
||||||
|
#define breezesizegrip_h
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#include "breezedecoration.h"
|
||||||
|
#include "config-breeze.h"
|
||||||
|
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <QPaintEvent>
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//* implements size grip for all widgets
|
||||||
|
class SizeGrip: public QWidget
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit SizeGrip( Decoration* );
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
virtual ~SizeGrip();
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
|
||||||
|
//* update background color
|
||||||
|
void updateActiveState();
|
||||||
|
|
||||||
|
//* update position
|
||||||
|
void updatePosition();
|
||||||
|
|
||||||
|
//* embed into parent widget
|
||||||
|
void embed();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//*@name event handlers
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//* paint
|
||||||
|
virtual void paintEvent( QPaintEvent* ) override;
|
||||||
|
|
||||||
|
//* mouse press
|
||||||
|
virtual void mousePressEvent( QMouseEvent* ) override;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* send resize event
|
||||||
|
void sendMoveResizeEvent( QPoint );
|
||||||
|
|
||||||
|
//* grip size
|
||||||
|
enum {
|
||||||
|
Offset = 0,
|
||||||
|
GripSize = 14
|
||||||
|
};
|
||||||
|
|
||||||
|
//* decoration
|
||||||
|
QPointer<Decoration> m_decoration;
|
||||||
|
|
||||||
|
//* move/resize atom
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
xcb_atom_t m_moveResizeAtom = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
20
cmake/Modules/FindFFTW.cmake
Normal file
20
cmake/Modules/FindFFTW.cmake
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# Find the FFTW library
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# find_package(FFTW [REQUIRED])
|
||||||
|
#
|
||||||
|
# It sets the following variables:
|
||||||
|
# FFTW_FOUND
|
||||||
|
# FFTW_INCLUDES
|
||||||
|
# FFTW_LIBRARIES
|
||||||
|
|
||||||
|
|
||||||
|
find_path(FFTW_INCLUDES fftw3.h)
|
||||||
|
|
||||||
|
find_library(FFTW_LIBRARIES NAMES fftw3)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(FFTW DEFAULT_MSG
|
||||||
|
FFTW_INCLUDES FFTW_LIBRARIES)
|
||||||
|
|
||||||
|
mark_as_advanced(FFTW_INCLUDES FFTW_LIBRARIES)
|
28
config-breeze.h.cmake
Normal file
28
config-breeze.h.cmake
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/* config-breeze.h. Generated by cmake from config-breeze.h.cmake */
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef config_breeze_h
|
||||||
|
#define config_breeze_h
|
||||||
|
|
||||||
|
/* Define to 1 if XCB libraries are found */
|
||||||
|
#cmakedefine01 BREEZE_HAVE_X11
|
||||||
|
|
||||||
|
#endif
|
15
config/breeze10config.desktop
Normal file
15
config/breeze10config.desktop
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Exec=kcmshell5 breeze10config
|
||||||
|
Icon=preferences-system-windows
|
||||||
|
Type=Service
|
||||||
|
X-KDE-ServiceTypes=KCModule
|
||||||
|
|
||||||
|
X-KDE-Library=org.kde.kdecoration2/breeze10
|
||||||
|
X-KDE-PluginKeyword=kcmodule
|
||||||
|
X-KDE-ParentApp=kcontrol
|
||||||
|
X-KDE-Weight=60
|
||||||
|
X-KDE-PluginInfo-Name=Breeze10
|
||||||
|
|
||||||
|
Name=Breeze10
|
||||||
|
Comment=Modify the appearance of window decorations
|
||||||
|
X-KDE-Keywords=breeze10,decoration
|
323
config/breezeconfigwidget.cpp
Normal file
323
config/breezeconfigwidget.cpp
Normal file
|
@ -0,0 +1,323 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeconfigurationui.cpp
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeconfigwidget.h"
|
||||||
|
#include "breezeexceptionlist.h"
|
||||||
|
#include "breezesettings.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
#include <QDBusConnection>
|
||||||
|
#include <QDBusMessage>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
ConfigWidget::ConfigWidget( QWidget* parent, const QVariantList &args ):
|
||||||
|
KCModule(parent, args),
|
||||||
|
m_configuration( KSharedConfig::openConfig( QStringLiteral( "breezerc" ) ) ),
|
||||||
|
m_changed( false )
|
||||||
|
{
|
||||||
|
|
||||||
|
// configuration
|
||||||
|
m_ui.setupUi( this );
|
||||||
|
|
||||||
|
// track ui changes
|
||||||
|
connect( m_ui.titleAlignment, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.buttonSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.drawBorderOnMaximizedWindows, SIGNAL(clicked()), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.drawSizeGrip, SIGNAL(clicked()), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.opacitySpinBox, QOverload<int>::of(&QSpinBox::valueChanged), [=](int /*i*/){updateChanged();} );
|
||||||
|
|
||||||
|
connect( m_ui.fontComboBox, &QFontComboBox::currentFontChanged, [this] { updateChanged(); } );
|
||||||
|
connect( m_ui.fontSizeSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), [=](int /*i*/){updateChanged();} );
|
||||||
|
connect(m_ui.weightComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this] { updateChanged(); } );
|
||||||
|
connect( m_ui.italicCheckBox, &QCheckBox::stateChanged, [this] { updateChanged(); } );
|
||||||
|
|
||||||
|
// track animations changes
|
||||||
|
connect( m_ui.animationsEnabled, SIGNAL(clicked()), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.animationsDuration, SIGNAL(valueChanged(int)), SLOT(updateChanged()) );
|
||||||
|
|
||||||
|
// track shadows changes
|
||||||
|
connect( m_ui.shadowSize, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.shadowStrength, SIGNAL(valueChanged(int)), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.shadowColor, SIGNAL(changed(QColor)), SLOT(updateChanged()) );
|
||||||
|
|
||||||
|
// track exception changes
|
||||||
|
connect( m_ui.exceptions, SIGNAL(changed(bool)), SLOT(updateChanged()) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
void ConfigWidget::load()
|
||||||
|
{
|
||||||
|
|
||||||
|
// create internal settings and load from rc files
|
||||||
|
m_internalSettings = InternalSettingsPtr( new InternalSettings() );
|
||||||
|
m_internalSettings->load();
|
||||||
|
|
||||||
|
// assign to ui
|
||||||
|
m_ui.titleAlignment->setCurrentIndex( m_internalSettings->titleAlignment() );
|
||||||
|
m_ui.buttonSize->setCurrentIndex( m_internalSettings->buttonSize() );
|
||||||
|
m_ui.drawBorderOnMaximizedWindows->setChecked( m_internalSettings->drawBorderOnMaximizedWindows() );
|
||||||
|
m_ui.drawSizeGrip->setChecked( m_internalSettings->drawSizeGrip() );
|
||||||
|
m_ui.animationsEnabled->setChecked( m_internalSettings->animationsEnabled() );
|
||||||
|
m_ui.animationsDuration->setValue( m_internalSettings->animationsDuration() );
|
||||||
|
m_ui.opacitySpinBox->setValue( m_internalSettings->backgroundOpacity() );
|
||||||
|
|
||||||
|
QString fontStr = m_internalSettings->titleBarFont();
|
||||||
|
if (fontStr.isEmpty())
|
||||||
|
fontStr = QLatin1String("Sans,11,-1,5,50,0,0,0,0,0");
|
||||||
|
QFont f; f.fromString( fontStr );
|
||||||
|
m_ui.fontComboBox->setCurrentFont( f );
|
||||||
|
m_ui.fontSizeSpinBox->setValue( f.pointSize() );
|
||||||
|
int w = f.weight();
|
||||||
|
switch (w) {
|
||||||
|
case QFont::Medium:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(1);
|
||||||
|
break;
|
||||||
|
case QFont::DemiBold:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(2);
|
||||||
|
break;
|
||||||
|
case QFont::Bold:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(3);
|
||||||
|
break;
|
||||||
|
case QFont::ExtraBold:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(4);
|
||||||
|
break;
|
||||||
|
case QFont::Black:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_ui.italicCheckBox->setChecked( f.italic() );
|
||||||
|
|
||||||
|
// load shadows
|
||||||
|
if( m_internalSettings->shadowSize() <= InternalSettings::ShadowVeryLarge ) m_ui.shadowSize->setCurrentIndex( m_internalSettings->shadowSize() );
|
||||||
|
else m_ui.shadowSize->setCurrentIndex( InternalSettings::ShadowLarge );
|
||||||
|
|
||||||
|
m_ui.shadowStrength->setValue( qRound(qreal(m_internalSettings->shadowStrength()*100)/255 ) );
|
||||||
|
m_ui.shadowColor->setColor( m_internalSettings->shadowColor() );
|
||||||
|
|
||||||
|
// load exceptions
|
||||||
|
ExceptionList exceptions;
|
||||||
|
exceptions.readConfig( m_configuration );
|
||||||
|
m_ui.exceptions->setExceptions( exceptions.get() );
|
||||||
|
setChanged( false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
void ConfigWidget::save()
|
||||||
|
{
|
||||||
|
|
||||||
|
// create internal settings and load from rc files
|
||||||
|
m_internalSettings = InternalSettingsPtr( new InternalSettings() );
|
||||||
|
m_internalSettings->load();
|
||||||
|
|
||||||
|
// apply modifications from ui
|
||||||
|
m_internalSettings->setTitleAlignment( m_ui.titleAlignment->currentIndex() );
|
||||||
|
m_internalSettings->setButtonSize( m_ui.buttonSize->currentIndex() );
|
||||||
|
m_internalSettings->setDrawBorderOnMaximizedWindows( m_ui.drawBorderOnMaximizedWindows->isChecked() );
|
||||||
|
m_internalSettings->setDrawSizeGrip( m_ui.drawSizeGrip->isChecked() );
|
||||||
|
m_internalSettings->setAnimationsEnabled( m_ui.animationsEnabled->isChecked() );
|
||||||
|
m_internalSettings->setAnimationsDuration( m_ui.animationsDuration->value() );
|
||||||
|
m_internalSettings->setBackgroundOpacity(m_ui.opacitySpinBox->value());
|
||||||
|
|
||||||
|
QFont f = m_ui.fontComboBox->currentFont();
|
||||||
|
f.setPointSize(m_ui.fontSizeSpinBox->value());
|
||||||
|
int indx = m_ui.weightComboBox->currentIndex();
|
||||||
|
switch (indx) {
|
||||||
|
case 1:
|
||||||
|
f.setWeight(QFont::Medium);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
f.setWeight(QFont::DemiBold);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
f.setWeight(QFont::Bold);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
f.setWeight(QFont::ExtraBold);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
f.setWeight(QFont::Black);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
f.setBold(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f.setItalic(m_ui.italicCheckBox->isChecked());
|
||||||
|
m_internalSettings->setTitleBarFont(f.toString());
|
||||||
|
|
||||||
|
m_internalSettings->setShadowSize( m_ui.shadowSize->currentIndex() );
|
||||||
|
m_internalSettings->setShadowStrength( qRound( qreal(m_ui.shadowStrength->value()*255)/100 ) );
|
||||||
|
m_internalSettings->setShadowColor( m_ui.shadowColor->color() );
|
||||||
|
|
||||||
|
// save configuration
|
||||||
|
m_internalSettings->save();
|
||||||
|
|
||||||
|
// get list of exceptions and write
|
||||||
|
InternalSettingsList exceptions( m_ui.exceptions->exceptions() );
|
||||||
|
ExceptionList( exceptions ).writeConfig( m_configuration );
|
||||||
|
|
||||||
|
// sync configuration
|
||||||
|
m_configuration->sync();
|
||||||
|
setChanged( false );
|
||||||
|
|
||||||
|
// needed to tell kwin to reload when running from external kcmshell
|
||||||
|
{
|
||||||
|
QDBusMessage message = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
|
||||||
|
QDBusConnection::sessionBus().send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
// needed for breeze style to reload shadows
|
||||||
|
{
|
||||||
|
QDBusMessage message( QDBusMessage::createSignal("/BreezeDecoration", "org.kde.Breeze.Style", "reparseConfiguration") );
|
||||||
|
QDBusConnection::sessionBus().send(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
void ConfigWidget::defaults()
|
||||||
|
{
|
||||||
|
|
||||||
|
// create internal settings and load from rc files
|
||||||
|
m_internalSettings = InternalSettingsPtr( new InternalSettings() );
|
||||||
|
m_internalSettings->setDefaults();
|
||||||
|
|
||||||
|
// assign to ui
|
||||||
|
m_ui.titleAlignment->setCurrentIndex( m_internalSettings->titleAlignment() );
|
||||||
|
m_ui.buttonSize->setCurrentIndex( m_internalSettings->buttonSize() );
|
||||||
|
m_ui.drawBorderOnMaximizedWindows->setChecked( m_internalSettings->drawBorderOnMaximizedWindows() );
|
||||||
|
m_ui.drawSizeGrip->setChecked( m_internalSettings->drawSizeGrip() );
|
||||||
|
m_ui.animationsEnabled->setChecked( m_internalSettings->animationsEnabled() );
|
||||||
|
m_ui.animationsDuration->setValue( m_internalSettings->animationsDuration() );
|
||||||
|
m_ui.opacitySpinBox->setValue( m_internalSettings->backgroundOpacity() );
|
||||||
|
|
||||||
|
QFont f; f.fromString("Sans,11,-1,5,50,0,0,0,0,0");
|
||||||
|
m_ui.fontComboBox->setCurrentFont( f );
|
||||||
|
m_ui.fontSizeSpinBox->setValue( f.pointSize() );
|
||||||
|
int w = f.weight();
|
||||||
|
switch (w) {
|
||||||
|
case QFont::Medium:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(1);
|
||||||
|
break;
|
||||||
|
case QFont::DemiBold:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(2);
|
||||||
|
break;
|
||||||
|
case QFont::Bold:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(3);
|
||||||
|
break;
|
||||||
|
case QFont::ExtraBold:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(4);
|
||||||
|
break;
|
||||||
|
case QFont::Black:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(5);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
m_ui.weightComboBox->setCurrentIndex(0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_ui.italicCheckBox->setChecked( f.italic() );
|
||||||
|
|
||||||
|
m_ui.shadowSize->setCurrentIndex( m_internalSettings->shadowSize() );
|
||||||
|
m_ui.shadowStrength->setValue( qRound(qreal(m_internalSettings->shadowStrength()*100)/255 ) );
|
||||||
|
m_ui.shadowColor->setColor( m_internalSettings->shadowColor() );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________
|
||||||
|
void ConfigWidget::updateChanged()
|
||||||
|
{
|
||||||
|
|
||||||
|
// check configuration
|
||||||
|
if( !m_internalSettings ) return;
|
||||||
|
|
||||||
|
// track modifications
|
||||||
|
bool modified( false );
|
||||||
|
QFont f; f.fromString( m_internalSettings->titleBarFont() );
|
||||||
|
|
||||||
|
if( m_ui.titleAlignment->currentIndex() != m_internalSettings->titleAlignment() ) modified = true;
|
||||||
|
else if( m_ui.buttonSize->currentIndex() != m_internalSettings->buttonSize() ) modified = true;
|
||||||
|
else if( m_ui.drawBorderOnMaximizedWindows->isChecked() != m_internalSettings->drawBorderOnMaximizedWindows() ) modified = true;
|
||||||
|
else if( m_ui.drawSizeGrip->isChecked() != m_internalSettings->drawSizeGrip() ) modified = true;
|
||||||
|
else if( m_ui.opacitySpinBox->value() != m_internalSettings->backgroundOpacity() ) modified = true;
|
||||||
|
|
||||||
|
// font (also see below)
|
||||||
|
else if( m_ui.fontComboBox->currentFont().toString() != f.family() ) modified = true;
|
||||||
|
else if( m_ui.fontSizeSpinBox->value() != f.pointSize() ) modified = true;
|
||||||
|
else if( m_ui.italicCheckBox->isChecked() != f.italic() ) modified = true;
|
||||||
|
|
||||||
|
// animations
|
||||||
|
else if( m_ui.animationsEnabled->isChecked() != m_internalSettings->animationsEnabled() ) modified = true;
|
||||||
|
else if( m_ui.animationsDuration->value() != m_internalSettings->animationsDuration() ) modified = true;
|
||||||
|
|
||||||
|
// shadows
|
||||||
|
else if( m_ui.shadowSize->currentIndex() != m_internalSettings->shadowSize() ) modified = true;
|
||||||
|
else if( qRound( qreal(m_ui.shadowStrength->value()*255)/100 ) != m_internalSettings->shadowStrength() ) modified = true;
|
||||||
|
else if( m_ui.shadowColor->color() != m_internalSettings->shadowColor() ) modified = true;
|
||||||
|
|
||||||
|
// exceptions
|
||||||
|
else if( m_ui.exceptions->isChanged() ) modified = true;
|
||||||
|
else {
|
||||||
|
int indx = m_ui.weightComboBox->currentIndex();
|
||||||
|
switch (indx) {
|
||||||
|
case 1:
|
||||||
|
if (f.weight() != QFont::Medium) modified = true;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (f.weight() != QFont::DemiBold) modified = true;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
if (f.weight() != QFont::Bold) modified = true;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (f.weight() != QFont::ExtraBold) modified = true;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
if (f.weight() != QFont::Black) modified = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (f.bold()) modified = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setChanged( modified );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________
|
||||||
|
void ConfigWidget::setChanged( bool value )
|
||||||
|
{
|
||||||
|
emit changed( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
93
config/breezeconfigwidget.h
Normal file
93
config/breezeconfigwidget.h
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
#ifndef breezeconfigwidget_h
|
||||||
|
#define breezeconfigwidget_h
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeconfigurationui.h
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "ui_breezeconfigurationui.h"
|
||||||
|
#include "breezeexceptionlistwidget.h"
|
||||||
|
#include "breezesettings.h"
|
||||||
|
#include "breeze.h"
|
||||||
|
|
||||||
|
#include <KCModule>
|
||||||
|
#include <KSharedConfig>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
#include <QSharedPointer>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//_____________________________________________
|
||||||
|
class ConfigWidget: public KCModule
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit ConfigWidget( QWidget*, const QVariantList& );
|
||||||
|
|
||||||
|
//* destructor
|
||||||
|
virtual ~ConfigWidget() = default;
|
||||||
|
|
||||||
|
//* default
|
||||||
|
void defaults() override;
|
||||||
|
|
||||||
|
//* load configuration
|
||||||
|
void load() override;
|
||||||
|
|
||||||
|
//* save configuration
|
||||||
|
void save() override;
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
|
||||||
|
//* update changed state
|
||||||
|
virtual void updateChanged();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* set changed state
|
||||||
|
void setChanged( bool );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* ui
|
||||||
|
Ui_BreezeConfigurationUI m_ui;
|
||||||
|
|
||||||
|
//* kconfiguration object
|
||||||
|
KSharedConfig::Ptr m_configuration;
|
||||||
|
|
||||||
|
//* internal exception
|
||||||
|
InternalSettingsPtr m_internalSettings;
|
||||||
|
|
||||||
|
//* changed state
|
||||||
|
bool m_changed;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
131
config/breezedecorationconfig.desktop
Normal file
131
config/breezedecorationconfig.desktop
Normal file
|
@ -0,0 +1,131 @@
|
||||||
|
[Desktop Entry]
|
||||||
|
Exec=kcmshell5 breezedecorationconfig
|
||||||
|
Icon=preferences-system-windows
|
||||||
|
Type=Service
|
||||||
|
X-KDE-ServiceTypes=KCModule
|
||||||
|
|
||||||
|
X-KDE-Library=org.kde.kdecoration2/breezedecoration
|
||||||
|
X-KDE-PluginKeyword=kcmodule
|
||||||
|
X-KDE-ParentApp=kcontrol
|
||||||
|
X-KDE-Weight=60
|
||||||
|
|
||||||
|
Name=Breeze Window Decoration
|
||||||
|
Name[ca]=Decoració de les finestres Brisa
|
||||||
|
Name[ca@valencia]=Decoració de les finestres Brisa
|
||||||
|
Name[cs]=Dekorace oken Breeze
|
||||||
|
Name[da]=Breeze vinduesdekoration
|
||||||
|
Name[de]=Breeze-Fensterdekoration
|
||||||
|
Name[el]=Διακοσμήσεις παραθύρου Breeze
|
||||||
|
Name[en_GB]=Breeze Window Decoration
|
||||||
|
Name[es]=Decoración de ventanas Brisa
|
||||||
|
Name[eu]=Breeze leihoen apaindura
|
||||||
|
Name[fi]=Breeze-ikkunankehys
|
||||||
|
Name[fr]=Décoration de fenêtre Brise
|
||||||
|
Name[gl]=Decoración de xanela de Breeze
|
||||||
|
Name[hu]=Breeze ablakdekoráció
|
||||||
|
Name[ia]=Decoration de fenestra Breeze
|
||||||
|
Name[id]=Dekorasi Jendela Breeze
|
||||||
|
Name[it]=Decorazione delle finestre di Brezza
|
||||||
|
Name[ko]=Breeze 창 장식
|
||||||
|
Name[nl]=Breeze vensterdecoratie
|
||||||
|
Name[nn]=Breeze-vindaugsdekorasjon
|
||||||
|
Name[pl]=Wygląd okien Bryzy
|
||||||
|
Name[pt]=Decoração de Janelas Brisa
|
||||||
|
Name[pt_BR]=Decorações da janela Breeze
|
||||||
|
Name[ru]=Оформление окон Breeze
|
||||||
|
Name[sk]=Dekorácie okien Breeze
|
||||||
|
Name[sl]=Okraski oken Sapica
|
||||||
|
Name[sr]=Поветарчева декорација прозора
|
||||||
|
Name[sr@ijekavian]=Поветарчева декорација прозора
|
||||||
|
Name[sr@ijekavianlatin]=Povetarčeva dekoracija prozora
|
||||||
|
Name[sr@latin]=Povetarčeva dekoracija prozora
|
||||||
|
Name[sv]=Breeze fönsterdekoration
|
||||||
|
Name[tr]=Breeze Pencere Dekorasyonu
|
||||||
|
Name[uk]=Декорації вікон Breeze
|
||||||
|
Name[x-test]=xxBreeze Window Decorationxx
|
||||||
|
Name[zh_CN]=微风窗口装饰
|
||||||
|
Name[zh_TW]=Breeze 視窗裝飾
|
||||||
|
Comment=Modify the appearance of window decorations
|
||||||
|
Comment[ar]=عدّل مظهر زخرفات النّوافذ
|
||||||
|
Comment[ca]=Modifica l'aparença de les decoracions de les finestres
|
||||||
|
Comment[ca@valencia]=Modifica l'aparença de les decoracions de les finestres
|
||||||
|
Comment[cs]=Změnit vzhled dekorace oken
|
||||||
|
Comment[da]=Ændr vinduesdekorationers udseende
|
||||||
|
Comment[de]=Das Erscheinungsbild der Fensterdekorationen ändern
|
||||||
|
Comment[el]=Τροποποίηση εμφάνισης της διακόσμησης παραθύρου
|
||||||
|
Comment[en_GB]=Modify the appearance of window decorations
|
||||||
|
Comment[es]=Modificar el aspecto de las decoraciones de las ventanas
|
||||||
|
Comment[et]=Akna dekoratsioonide välimuse muutmine
|
||||||
|
Comment[eu]=Aldatu leiho apainduren itxura
|
||||||
|
Comment[fi]=Muuta ikkunoiden kehysten ulkoasua
|
||||||
|
Comment[fr]=Modifier l'apparence des décorations des fenêtres
|
||||||
|
Comment[gl]=Modifica a aparencia da decoración da xanela
|
||||||
|
Comment[he]=התאם את מראה מסגרות החלונות
|
||||||
|
Comment[hu]=Az ablakdekorációk megjelenésének módosítása
|
||||||
|
Comment[ia]=Modifica le apparentia de decorationes de fenestra
|
||||||
|
Comment[id]=Memodofikasi penampilan dekorasi jendela
|
||||||
|
Comment[it]=Modifica l'aspetto delle decorazioni delle finestre
|
||||||
|
Comment[ko]=창 장식의 모습을 수정합니다
|
||||||
|
Comment[lt]=Keisti lango dekoracijų išvaizdą
|
||||||
|
Comment[nb]=Endre utseende for vindusdekorasjoner
|
||||||
|
Comment[nl]=Wijzig het uiterlijk van vensterdecoraties
|
||||||
|
Comment[nn]=Endra utsjånad på vindaugspynt
|
||||||
|
Comment[pl]=Zmień wygląd i wystrój okien
|
||||||
|
Comment[pt]=Modificar a aparência das decorações das janelas
|
||||||
|
Comment[pt_BR]=Modifica a aparência das decorações da janela
|
||||||
|
Comment[ro]=Modifică aspectul decorațiilor pentru ferestre
|
||||||
|
Comment[ru]=Настройка заголовков окон в стиле Breeze
|
||||||
|
Comment[sk]=Zmena vzhľadu dekorácie okien
|
||||||
|
Comment[sl]=Spremenite videz okraskov oken
|
||||||
|
Comment[sr]=Измените изглед декорација прозора
|
||||||
|
Comment[sr@ijekavian]=Измијените изглед декорација прозора
|
||||||
|
Comment[sr@ijekavianlatin]=Izmijenite izgled dekoracija prozora
|
||||||
|
Comment[sr@latin]=Izmenite izgled dekoracija prozora
|
||||||
|
Comment[sv]=Ändra utseendet hos fönsterdekorationer
|
||||||
|
Comment[tr]=Pencere dekorasyonlarının görünümünü değiştir
|
||||||
|
Comment[uk]=Зміна вигляду декорацій вікон
|
||||||
|
Comment[x-test]=xxModify the appearance of window decorationsxx
|
||||||
|
Comment[zh_CN]=修改窗口装饰外观
|
||||||
|
Comment[zh_TW]=變更視窗裝飾外觀
|
||||||
|
X-KDE-Keywords=breeze,decoration
|
||||||
|
X-KDE-Keywords[ar]=نسيم,زخرفة
|
||||||
|
X-KDE-Keywords[ca]=breeze,brisa,decoració
|
||||||
|
X-KDE-Keywords[ca@valencia]=breeze,brisa,decoració
|
||||||
|
X-KDE-Keywords[cs]=breeze,dekorace
|
||||||
|
X-KDE-Keywords[da]=breeze,dekoration
|
||||||
|
X-KDE-Keywords[de]=Breeze-Dekoration
|
||||||
|
X-KDE-Keywords[el]=breeze,διακόσμηση
|
||||||
|
X-KDE-Keywords[en_GB]=breeze,decoration
|
||||||
|
X-KDE-Keywords[es]=breeze,brisa,decoración
|
||||||
|
X-KDE-Keywords[et]=breeze,dekoratsioon
|
||||||
|
X-KDE-Keywords[eu]=breeze,apainketa,apaindura
|
||||||
|
X-KDE-Keywords[fi]=breeze,decoration,kehys,koriste,koristus,ikkunakehys
|
||||||
|
X-KDE-Keywords[fr]=breeze,décoration
|
||||||
|
X-KDE-Keywords[gl]=breeze,decoración
|
||||||
|
X-KDE-Keywords[he]=breeze,decoration,מסגרת
|
||||||
|
X-KDE-Keywords[hu]=breeze,dekoráció
|
||||||
|
X-KDE-Keywords[ia]=breeze,decoration
|
||||||
|
X-KDE-Keywords[id]=breeze,dekorasi
|
||||||
|
X-KDE-Keywords[it]=brezza,decorazione
|
||||||
|
X-KDE-Keywords[ko]=breeze,decoration,장식
|
||||||
|
X-KDE-Keywords[lt]=breeze,kekoracija
|
||||||
|
X-KDE-Keywords[nb]=beeze,dekorasjon
|
||||||
|
X-KDE-Keywords[nl]=breeze,decoratie
|
||||||
|
X-KDE-Keywords[nn]=breeze,dekorasjonar,pynt
|
||||||
|
X-KDE-Keywords[pl]=breeze,dekoracja,bryza,wystrój
|
||||||
|
X-KDE-Keywords[pt]=brisa,decoração
|
||||||
|
X-KDE-Keywords[pt_BR]=breeze,decoração
|
||||||
|
X-KDE-Keywords[ro]=briză,breeze,decorare,decorație
|
||||||
|
X-KDE-Keywords[ru]=breeze,бриз,decoration,декорации окон,оформление окон
|
||||||
|
X-KDE-Keywords[sk]=breeze,dekorácia
|
||||||
|
X-KDE-Keywords[sl]=sapica,okraski
|
||||||
|
X-KDE-Keywords[sr]=breeze,decoration,Поветарац,декорација
|
||||||
|
X-KDE-Keywords[sr@ijekavian]=breeze,decoration,Поветарац,декорација
|
||||||
|
X-KDE-Keywords[sr@ijekavianlatin]=breeze,decoration,Povetarac,dekoracija
|
||||||
|
X-KDE-Keywords[sr@latin]=breeze,decoration,Povetarac,dekoracija
|
||||||
|
X-KDE-Keywords[sv]=breeze,dekoration
|
||||||
|
X-KDE-Keywords[tr]=esinti,dekorasyon
|
||||||
|
X-KDE-Keywords[uk]=breeze,decoration,бриз,декорації,декорація,обрамлення
|
||||||
|
X-KDE-Keywords[x-test]=xxbreezexx,xxdecorationxx
|
||||||
|
X-KDE-Keywords[zh_CN]=breeze,decoration,微风,装饰
|
||||||
|
X-KDE-Keywords[zh_TW]=breeze,decoration
|
182
config/breezedetectwidget.cpp
Normal file
182
config/breezedetectwidget.cpp
Normal file
|
@ -0,0 +1,182 @@
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezedetectwidget.cpp
|
||||||
|
// Note: this class is a stripped down version of
|
||||||
|
// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.cpp
|
||||||
|
// Copyright (c) 2004 Lubos Lunak <l.lunak@kde.org>
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezedetectwidget.h"
|
||||||
|
|
||||||
|
#include "breeze.h"
|
||||||
|
|
||||||
|
#include <KWindowInfo>
|
||||||
|
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QMouseEvent>
|
||||||
|
#include <config-breeze.h>
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
#include <QX11Info>
|
||||||
|
#include <xcb/xcb.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
DetectDialog::DetectDialog( QWidget* parent ):
|
||||||
|
QDialog( parent )
|
||||||
|
{
|
||||||
|
|
||||||
|
// setup
|
||||||
|
m_ui.setupUi( this );
|
||||||
|
|
||||||
|
connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL(clicked()), this, SLOT(close()) );
|
||||||
|
m_ui.windowClassCheckBox->setChecked( true );
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if (QX11Info::isPlatformX11()) {
|
||||||
|
// create atom
|
||||||
|
xcb_connection_t* connection( QX11Info::connection() );
|
||||||
|
const QString atomName( QStringLiteral( "WM_STATE" ) );
|
||||||
|
xcb_intern_atom_cookie_t cookie( xcb_intern_atom( connection, false, atomName.size(), qPrintable( atomName ) ) );
|
||||||
|
QScopedPointer<xcb_intern_atom_reply_t, QScopedPointerPodDeleter> reply( xcb_intern_atom_reply( connection, cookie, nullptr) );
|
||||||
|
m_wmStateAtom = reply ? reply->atom : 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
void DetectDialog::detect( WId window )
|
||||||
|
{
|
||||||
|
if( window == 0 ) selectWindow();
|
||||||
|
else readWindow( window );
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
void DetectDialog::readWindow( WId window )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( window == 0 )
|
||||||
|
{
|
||||||
|
emit detectionDone( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_info.reset(new KWindowInfo( window, NET::WMAllProperties, NET::WM2AllProperties ));
|
||||||
|
if( !m_info->valid())
|
||||||
|
{
|
||||||
|
emit detectionDone( false );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QString wmClassClass( QString::fromUtf8( m_info->windowClassClass() ) );
|
||||||
|
const QString wmClassName( QString::fromUtf8( m_info->windowClassName() ) );
|
||||||
|
|
||||||
|
m_ui.windowClass->setText( QStringLiteral( "%1 (%2 %3)" ).arg( wmClassClass ).arg( wmClassName ).arg( wmClassClass ) );
|
||||||
|
m_ui.windowTitle->setText( m_info->name() );
|
||||||
|
emit detectionDone( exec() == QDialog::Accepted );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
void DetectDialog::selectWindow()
|
||||||
|
{
|
||||||
|
|
||||||
|
// use a dialog, so that all user input is blocked
|
||||||
|
// use WX11BypassWM and moving away so that it's not actually visible
|
||||||
|
// grab only mouse, so that keyboard can be used e.g. for switching windows
|
||||||
|
m_grabber = new QDialog( nullptr, Qt::X11BypassWindowManagerHint );
|
||||||
|
m_grabber->move( -1000, -1000 );
|
||||||
|
m_grabber->setModal( true );
|
||||||
|
m_grabber->show();
|
||||||
|
|
||||||
|
// need to explicitly override cursor for Qt5
|
||||||
|
qApp->setOverrideCursor( Qt::CrossCursor );
|
||||||
|
m_grabber->grabMouse( Qt::CrossCursor );
|
||||||
|
m_grabber->installEventFilter( this );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
bool DetectDialog::eventFilter( QObject* o, QEvent* e )
|
||||||
|
{
|
||||||
|
// check object and event type
|
||||||
|
if( o != m_grabber ) return false;
|
||||||
|
if( e->type() != QEvent::MouseButtonRelease ) return false;
|
||||||
|
|
||||||
|
// need to explicitely release cursor for Qt5
|
||||||
|
qApp->restoreOverrideCursor();
|
||||||
|
|
||||||
|
// delete old m_grabber
|
||||||
|
delete m_grabber;
|
||||||
|
m_grabber = nullptr;
|
||||||
|
|
||||||
|
// check button
|
||||||
|
if( static_cast< QMouseEvent* >( e )->button() != Qt::LeftButton ) return true;
|
||||||
|
|
||||||
|
// read window information
|
||||||
|
readWindow( findWindow() );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//_________________________________________________________
|
||||||
|
WId DetectDialog::findWindow()
|
||||||
|
{
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if (!QX11Info::isPlatformX11()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// check atom
|
||||||
|
if( !m_wmStateAtom ) return 0;
|
||||||
|
|
||||||
|
xcb_connection_t* connection( QX11Info::connection() );
|
||||||
|
xcb_window_t parent( QX11Info::appRootWindow() );
|
||||||
|
|
||||||
|
// why is there a loop of only 10 here
|
||||||
|
for( int i = 0; i < 10; ++i )
|
||||||
|
{
|
||||||
|
|
||||||
|
// query pointer
|
||||||
|
xcb_query_pointer_cookie_t pointerCookie( xcb_query_pointer( connection, parent ) );
|
||||||
|
QScopedPointer<xcb_query_pointer_reply_t, QScopedPointerPodDeleter> pointerReply( xcb_query_pointer_reply( connection, pointerCookie, nullptr ) );
|
||||||
|
if( !( pointerReply && pointerReply->child ) ) return 0;
|
||||||
|
|
||||||
|
const xcb_window_t child( pointerReply->child );
|
||||||
|
xcb_get_property_cookie_t cookie( xcb_get_property( connection, 0, child, m_wmStateAtom, XCB_GET_PROPERTY_TYPE_ANY, 0, 0 ) );
|
||||||
|
QScopedPointer<xcb_get_property_reply_t, QScopedPointerPodDeleter> reply( xcb_get_property_reply( connection, cookie, nullptr ) );
|
||||||
|
if( reply && reply->type ) return child;
|
||||||
|
else parent = child;
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
113
config/breezedetectwidget.h
Normal file
113
config/breezedetectwidget.h
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
#ifndef breezedetectwidget_h
|
||||||
|
#define breezedetectwidget_h
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezedetectwidget.h
|
||||||
|
// Note: this class is a stripped down version of
|
||||||
|
// /kdebase/workspace/kwin/kcmkwin/kwinrules/detectwidget.h
|
||||||
|
// Copyright (c) 2004 Lubos Lunak <l.lunak@kde.org>
|
||||||
|
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezesettings.h"
|
||||||
|
#include "ui_breezedetectwidget.h"
|
||||||
|
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QEvent>
|
||||||
|
#include <QLabel>
|
||||||
|
|
||||||
|
#include <kwindowsystem.h>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
class DetectDialog : public QDialog
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit DetectDialog( QWidget* );
|
||||||
|
|
||||||
|
//* read window properties or select one from mouse grab
|
||||||
|
void detect( WId window );
|
||||||
|
|
||||||
|
//* selected class
|
||||||
|
QByteArray selectedClass() const;
|
||||||
|
|
||||||
|
//* window information
|
||||||
|
const KWindowInfo& windowInfo() const
|
||||||
|
{ return *(m_info.data()); }
|
||||||
|
|
||||||
|
//* exception type
|
||||||
|
InternalSettings::EnumExceptionType exceptionType() const
|
||||||
|
{
|
||||||
|
if( m_ui.windowClassCheckBox->isChecked() ) return InternalSettings::ExceptionWindowClassName;
|
||||||
|
else if( m_ui.windowTitleCheckBox->isChecked() ) return InternalSettings::ExceptionWindowTitle;
|
||||||
|
else return InternalSettings::ExceptionWindowClassName;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
void detectionDone( bool );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
bool eventFilter( QObject* o, QEvent* e ) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* select window from grab
|
||||||
|
void selectWindow();
|
||||||
|
|
||||||
|
//* read window properties
|
||||||
|
void readWindow( WId window );
|
||||||
|
|
||||||
|
//* find window under cursor
|
||||||
|
WId findWindow();
|
||||||
|
|
||||||
|
//* execute
|
||||||
|
void executeDialog();
|
||||||
|
|
||||||
|
//* ui
|
||||||
|
Ui::BreezeDetectWidget m_ui;
|
||||||
|
|
||||||
|
//* invisible dialog used to grab mouse
|
||||||
|
QDialog* m_grabber = nullptr;
|
||||||
|
|
||||||
|
//* current window information
|
||||||
|
QScopedPointer<KWindowInfo> m_info;
|
||||||
|
|
||||||
|
//* wm state atom
|
||||||
|
quint32 m_wmStateAtom = 0;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
#endif
|
197
config/breezeexceptiondialog.cpp
Normal file
197
config/breezeexceptiondialog.cpp
Normal file
|
@ -0,0 +1,197 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptiondialog.cpp
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeexceptiondialog.h"
|
||||||
|
#include "breezedetectwidget.h"
|
||||||
|
#include "config-breeze.h"
|
||||||
|
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
#include <QX11Info>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
ExceptionDialog::ExceptionDialog( QWidget* parent ):
|
||||||
|
QDialog( parent )
|
||||||
|
{
|
||||||
|
|
||||||
|
m_ui.setupUi( this );
|
||||||
|
|
||||||
|
connect( m_ui.buttonBox->button( QDialogButtonBox::Cancel ), SIGNAL(clicked()), this, SLOT(close()) );
|
||||||
|
|
||||||
|
// store checkboxes from ui into list
|
||||||
|
m_checkboxes.insert( BorderSize, m_ui.borderSizeCheckBox );
|
||||||
|
|
||||||
|
// detect window properties
|
||||||
|
connect( m_ui.detectDialogButton, SIGNAL(clicked()), SLOT(selectWindowProperties()) );
|
||||||
|
|
||||||
|
// connections
|
||||||
|
connect( m_ui.exceptionType, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.exceptionEditor, SIGNAL(textChanged(QString)), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.borderSizeComboBox, SIGNAL(currentIndexChanged(int)), SLOT(updateChanged()) );
|
||||||
|
|
||||||
|
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
|
||||||
|
{ connect( iter.value(), SIGNAL(clicked()), SLOT(updateChanged()) ); }
|
||||||
|
|
||||||
|
connect( m_ui.hideTitleBar, SIGNAL(clicked()), SLOT(updateChanged()) );
|
||||||
|
connect( m_ui.opaqueTitleBar, SIGNAL(clicked()), SLOT(updateChanged()) );
|
||||||
|
m_ui.opacityOverrideLabelSpinBox->setSpecialValueText(tr("None"));
|
||||||
|
connect( m_ui.opacityOverrideLabelSpinBox, QOverload<int>::of(&QSpinBox::valueChanged), [=](int /*i*/){updateChanged();} );
|
||||||
|
connect( m_ui.isDialog, SIGNAL(clicked()), SLOT(updateChanged()) );
|
||||||
|
|
||||||
|
// hide detection dialog on non X11 platforms
|
||||||
|
#if BREEZE_HAVE_X11
|
||||||
|
if( !QX11Info::isPlatformX11() ) m_ui.detectDialogButton->hide();
|
||||||
|
#else
|
||||||
|
m_ui.detectDialogButton->hide();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
void ExceptionDialog::setException( InternalSettingsPtr exception )
|
||||||
|
{
|
||||||
|
|
||||||
|
// store exception internally
|
||||||
|
m_exception = exception;
|
||||||
|
|
||||||
|
// type
|
||||||
|
m_ui.exceptionType->setCurrentIndex(m_exception->exceptionType() );
|
||||||
|
m_ui.exceptionEditor->setText( m_exception->exceptionPattern() );
|
||||||
|
m_ui.borderSizeComboBox->setCurrentIndex( m_exception->borderSize() );
|
||||||
|
m_ui.hideTitleBar->setChecked( m_exception->hideTitleBar() );
|
||||||
|
m_ui.opaqueTitleBar->setChecked( m_exception->opaqueTitleBar() );
|
||||||
|
m_ui.opacityOverrideLabelSpinBox->setValue( m_exception->opacityOverride() );
|
||||||
|
m_ui.isDialog->setChecked( m_exception->isDialog() );
|
||||||
|
|
||||||
|
// mask
|
||||||
|
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
|
||||||
|
{ iter.value()->setChecked( m_exception->mask() & iter.key() ); }
|
||||||
|
|
||||||
|
setChanged( false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
void ExceptionDialog::save()
|
||||||
|
{
|
||||||
|
m_exception->setExceptionType( m_ui.exceptionType->currentIndex() );
|
||||||
|
m_exception->setExceptionPattern( m_ui.exceptionEditor->text() );
|
||||||
|
m_exception->setBorderSize( m_ui.borderSizeComboBox->currentIndex() );
|
||||||
|
m_exception->setHideTitleBar( m_ui.hideTitleBar->isChecked() );
|
||||||
|
m_exception->setOpaqueTitleBar( m_ui.opaqueTitleBar->isChecked() );
|
||||||
|
m_exception->setOpacityOverride( m_ui.opacityOverrideLabelSpinBox->value() );
|
||||||
|
m_exception->setIsDialog( m_ui.isDialog->isChecked() );
|
||||||
|
|
||||||
|
// mask
|
||||||
|
unsigned int mask = None;
|
||||||
|
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
|
||||||
|
{ if( iter.value()->isChecked() ) mask |= iter.key(); }
|
||||||
|
|
||||||
|
m_exception->setMask( mask );
|
||||||
|
|
||||||
|
setChanged( false );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
void ExceptionDialog::updateChanged()
|
||||||
|
{
|
||||||
|
bool modified( false );
|
||||||
|
if( m_exception->exceptionType() != m_ui.exceptionType->currentIndex() ) modified = true;
|
||||||
|
else if( m_exception->exceptionPattern() != m_ui.exceptionEditor->text() ) modified = true;
|
||||||
|
else if( m_exception->borderSize() != m_ui.borderSizeComboBox->currentIndex() ) modified = true;
|
||||||
|
else if( m_exception->hideTitleBar() != m_ui.hideTitleBar->isChecked() ) modified = true;
|
||||||
|
else if( m_exception->opaqueTitleBar() != m_ui.opaqueTitleBar->isChecked() ) modified = true;
|
||||||
|
else if( m_exception->opacityOverride() != m_ui.opacityOverrideLabelSpinBox->value() ) modified = true;
|
||||||
|
else if( m_exception->isDialog() != m_ui.isDialog->isChecked() ) modified = true;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// check mask
|
||||||
|
for( CheckBoxMap::iterator iter = m_checkboxes.begin(); iter != m_checkboxes.end(); ++iter )
|
||||||
|
{
|
||||||
|
if( iter.value()->isChecked() != (bool)( m_exception->mask() & iter.key() ) )
|
||||||
|
{
|
||||||
|
modified = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setChanged( modified );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
void ExceptionDialog::selectWindowProperties()
|
||||||
|
{
|
||||||
|
|
||||||
|
// create widget
|
||||||
|
if( !m_detectDialog )
|
||||||
|
{
|
||||||
|
m_detectDialog = new DetectDialog( this );
|
||||||
|
connect( m_detectDialog, SIGNAL(detectionDone(bool)), SLOT(readWindowProperties(bool)) );
|
||||||
|
}
|
||||||
|
|
||||||
|
m_detectDialog->detect(0);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//___________________________________________
|
||||||
|
void ExceptionDialog::readWindowProperties( bool valid )
|
||||||
|
{
|
||||||
|
Q_CHECK_PTR( m_detectDialog );
|
||||||
|
if( valid )
|
||||||
|
{
|
||||||
|
|
||||||
|
// type
|
||||||
|
m_ui.exceptionType->setCurrentIndex( m_detectDialog->exceptionType() );
|
||||||
|
|
||||||
|
// window info
|
||||||
|
const KWindowInfo& info( m_detectDialog->windowInfo() );
|
||||||
|
|
||||||
|
switch( m_detectDialog->exceptionType() )
|
||||||
|
{
|
||||||
|
|
||||||
|
default:
|
||||||
|
case InternalSettings::ExceptionWindowClassName:
|
||||||
|
m_ui.exceptionEditor->setText( QString::fromUtf8( info.windowClassClass() ) );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InternalSettings::ExceptionWindowTitle:
|
||||||
|
m_ui.exceptionEditor->setText( info.name() );
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
delete m_detectDialog;
|
||||||
|
m_detectDialog = nullptr;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
114
config/breezeexceptiondialog.h
Normal file
114
config/breezeexceptiondialog.h
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
#ifndef breezeexceptiondialog_h
|
||||||
|
#define breezeexceptiondialog_h
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptiondialog.h
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "ui_breezeexceptiondialog.h"
|
||||||
|
#include "breeze.h"
|
||||||
|
|
||||||
|
#include <QCheckBox>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
class DetectDialog;
|
||||||
|
|
||||||
|
//* breeze exceptions list
|
||||||
|
class ExceptionDialog: public QDialog
|
||||||
|
{
|
||||||
|
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit ExceptionDialog( QWidget* parent );
|
||||||
|
|
||||||
|
//* destructor
|
||||||
|
virtual ~ExceptionDialog()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//* set exception
|
||||||
|
void setException( InternalSettingsPtr );
|
||||||
|
|
||||||
|
//* save exception
|
||||||
|
void save();
|
||||||
|
|
||||||
|
//* true if changed
|
||||||
|
virtual bool isChanged() const
|
||||||
|
{ return m_changed; }
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
//* emmited when changed
|
||||||
|
void changed( bool );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* set changed state
|
||||||
|
virtual void setChanged( bool value )
|
||||||
|
{
|
||||||
|
m_changed = value;
|
||||||
|
emit changed( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
|
||||||
|
//* check whether configuration is changed and emit appropriate signal if yes
|
||||||
|
virtual void updateChanged();
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
|
||||||
|
//* select window properties from grabbed pointers
|
||||||
|
void selectWindowProperties();
|
||||||
|
|
||||||
|
//* read properties of selected window
|
||||||
|
void readWindowProperties( bool );
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* map mask and checkbox
|
||||||
|
using CheckBoxMap=QMap< ExceptionMask, QCheckBox*>;
|
||||||
|
|
||||||
|
Ui::BreezeExceptionDialog m_ui;
|
||||||
|
|
||||||
|
//* map mask and checkbox
|
||||||
|
CheckBoxMap m_checkboxes;
|
||||||
|
|
||||||
|
//* internal exception
|
||||||
|
InternalSettingsPtr m_exception;
|
||||||
|
|
||||||
|
//* detection dialog
|
||||||
|
DetectDialog* m_detectDialog = nullptr;
|
||||||
|
|
||||||
|
//* changed state
|
||||||
|
bool m_changed = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
345
config/breezeexceptionlistwidget.cpp
Normal file
345
config/breezeexceptionlistwidget.cpp
Normal file
|
@ -0,0 +1,345 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptionlistwidget.cpp
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeexceptionlistwidget.h"
|
||||||
|
#include "breezeexceptiondialog.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPointer>
|
||||||
|
#include <QIcon>
|
||||||
|
|
||||||
|
//__________________________________________________________
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//__________________________________________________________
|
||||||
|
ExceptionListWidget::ExceptionListWidget( QWidget* parent ):
|
||||||
|
QWidget( parent )
|
||||||
|
{
|
||||||
|
|
||||||
|
// ui
|
||||||
|
m_ui.setupUi( this );
|
||||||
|
|
||||||
|
// list
|
||||||
|
m_ui.exceptionListView->setAllColumnsShowFocus( true );
|
||||||
|
m_ui.exceptionListView->setRootIsDecorated( false );
|
||||||
|
m_ui.exceptionListView->setSortingEnabled( false );
|
||||||
|
m_ui.exceptionListView->setModel( &model() );
|
||||||
|
m_ui.exceptionListView->sortByColumn( ExceptionModel::ColumnType );
|
||||||
|
m_ui.exceptionListView->setSizePolicy( QSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Ignored ) );
|
||||||
|
|
||||||
|
m_ui.moveUpButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-up" ) ) );
|
||||||
|
m_ui.moveDownButton->setIcon( QIcon::fromTheme( QStringLiteral( "arrow-down" ) ) );
|
||||||
|
m_ui.addButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-add" ) ) );
|
||||||
|
m_ui.removeButton->setIcon( QIcon::fromTheme( QStringLiteral( "list-remove" ) ) );
|
||||||
|
m_ui.editButton->setIcon( QIcon::fromTheme( QStringLiteral( "edit-rename" ) ) );
|
||||||
|
|
||||||
|
connect( m_ui.addButton, SIGNAL(clicked()), SLOT(add()) );
|
||||||
|
connect( m_ui.editButton, SIGNAL(clicked()), SLOT(edit()) );
|
||||||
|
connect( m_ui.removeButton, SIGNAL(clicked()), SLOT(remove()) );
|
||||||
|
connect( m_ui.moveUpButton, SIGNAL(clicked()), SLOT(up()) );
|
||||||
|
connect( m_ui.moveDownButton, SIGNAL(clicked()), SLOT(down()) );
|
||||||
|
|
||||||
|
connect( m_ui.exceptionListView, SIGNAL(activated(QModelIndex)), SLOT(edit()) );
|
||||||
|
connect( m_ui.exceptionListView, SIGNAL(clicked(QModelIndex)), SLOT(toggle(QModelIndex)) );
|
||||||
|
connect( m_ui.exceptionListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)), SLOT(updateButtons()) );
|
||||||
|
|
||||||
|
updateButtons();
|
||||||
|
resizeColumns();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________
|
||||||
|
void ExceptionListWidget::setExceptions( const InternalSettingsList& exceptions )
|
||||||
|
{
|
||||||
|
model().set( exceptions );
|
||||||
|
resizeColumns();
|
||||||
|
setChanged( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________
|
||||||
|
InternalSettingsList ExceptionListWidget::exceptions()
|
||||||
|
{
|
||||||
|
return model().get();
|
||||||
|
setChanged( false );
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________
|
||||||
|
void ExceptionListWidget::updateButtons()
|
||||||
|
{
|
||||||
|
|
||||||
|
bool hasSelection( !m_ui.exceptionListView->selectionModel()->selectedRows().empty() );
|
||||||
|
m_ui.removeButton->setEnabled( hasSelection );
|
||||||
|
m_ui.editButton->setEnabled( hasSelection );
|
||||||
|
|
||||||
|
m_ui.moveUpButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( 0, QModelIndex() ) );
|
||||||
|
m_ui.moveDownButton->setEnabled( hasSelection && !m_ui.exceptionListView->selectionModel()->isRowSelected( model().rowCount()-1, QModelIndex() ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::add()
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
QPointer<ExceptionDialog> dialog = new ExceptionDialog( this );
|
||||||
|
dialog->setWindowTitle( i18n( "New Exception - Breeze Settings" ) );
|
||||||
|
InternalSettingsPtr exception( new InternalSettings() );
|
||||||
|
|
||||||
|
exception->load();
|
||||||
|
|
||||||
|
dialog->setException( exception );
|
||||||
|
|
||||||
|
// run dialog and check existence
|
||||||
|
if( !dialog->exec() )
|
||||||
|
{
|
||||||
|
delete dialog;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog->save();
|
||||||
|
delete dialog;
|
||||||
|
|
||||||
|
// check exceptions
|
||||||
|
if( !checkException( exception ) ) return;
|
||||||
|
|
||||||
|
// create new item
|
||||||
|
model().add( exception );
|
||||||
|
setChanged( true );
|
||||||
|
|
||||||
|
// make sure item is selected
|
||||||
|
QModelIndex index( model().index( exception ) );
|
||||||
|
if( index != m_ui.exceptionListView->selectionModel()->currentIndex() )
|
||||||
|
{
|
||||||
|
m_ui.exceptionListView->selectionModel()->select( index, QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
|
||||||
|
m_ui.exceptionListView->selectionModel()->setCurrentIndex( index, QItemSelectionModel::Current|QItemSelectionModel::Rows );
|
||||||
|
}
|
||||||
|
|
||||||
|
resizeColumns();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::edit()
|
||||||
|
{
|
||||||
|
|
||||||
|
// retrieve selection
|
||||||
|
QModelIndex current( m_ui.exceptionListView->selectionModel()->currentIndex() );
|
||||||
|
if( ! model().contains( current ) ) return;
|
||||||
|
|
||||||
|
InternalSettingsPtr exception( model().get( current ) );
|
||||||
|
|
||||||
|
// create dialog
|
||||||
|
QPointer<ExceptionDialog> dialog( new ExceptionDialog( this ) );
|
||||||
|
dialog->setWindowTitle( i18n( "Edit Exception - Breeze Settings" ) );
|
||||||
|
dialog->setException( exception );
|
||||||
|
|
||||||
|
// map dialog
|
||||||
|
if( !dialog->exec() )
|
||||||
|
{
|
||||||
|
delete dialog;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check modifications
|
||||||
|
if( !dialog->isChanged() ) return;
|
||||||
|
|
||||||
|
// retrieve exception
|
||||||
|
dialog->save();
|
||||||
|
delete dialog;
|
||||||
|
|
||||||
|
// check new exception validity
|
||||||
|
checkException( exception );
|
||||||
|
resizeColumns();
|
||||||
|
|
||||||
|
setChanged( true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::remove()
|
||||||
|
{
|
||||||
|
|
||||||
|
// confirmation dialog
|
||||||
|
{
|
||||||
|
QMessageBox messageBox( QMessageBox::Question, i18n("Question - Breeze Settings" ), i18n("Remove selected exception?"), QMessageBox::Yes | QMessageBox::Cancel );
|
||||||
|
messageBox.button( QMessageBox::Yes )->setText( i18n("Remove") );
|
||||||
|
messageBox.setDefaultButton( QMessageBox::Cancel );
|
||||||
|
if( messageBox.exec() == QMessageBox::Cancel ) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove
|
||||||
|
model().remove( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
|
||||||
|
resizeColumns();
|
||||||
|
updateButtons();
|
||||||
|
|
||||||
|
setChanged( true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::toggle( const QModelIndex& index )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( !model().contains( index ) ) return;
|
||||||
|
if( index.column() != ExceptionModel::ColumnEnabled ) return;
|
||||||
|
|
||||||
|
// get matching exception
|
||||||
|
InternalSettingsPtr exception( model().get( index ) );
|
||||||
|
exception->setEnabled( !exception->enabled() );
|
||||||
|
setChanged( true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::up()
|
||||||
|
{
|
||||||
|
|
||||||
|
InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
|
||||||
|
if( selection.empty() ) { return; }
|
||||||
|
|
||||||
|
// retrieve selected indexes in list and store in model
|
||||||
|
QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedRows() );
|
||||||
|
InternalSettingsList selectedExceptions( model().get( selectedIndices ) );
|
||||||
|
|
||||||
|
InternalSettingsList currentException( model().get() );
|
||||||
|
InternalSettingsList newExceptions;
|
||||||
|
|
||||||
|
for( InternalSettingsList::const_iterator iter = currentException.constBegin(); iter != currentException.constEnd(); ++iter )
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if new list is not empty, current index is selected and last index is not.
|
||||||
|
// if yes, move.
|
||||||
|
if(
|
||||||
|
!( newExceptions.empty() ||
|
||||||
|
selectedIndices.indexOf( model().index( *iter ) ) == -1 ||
|
||||||
|
selectedIndices.indexOf( model().index( newExceptions.back() ) ) != -1
|
||||||
|
) )
|
||||||
|
{
|
||||||
|
InternalSettingsPtr last( newExceptions.back() );
|
||||||
|
newExceptions.removeLast();
|
||||||
|
newExceptions.append( *iter );
|
||||||
|
newExceptions.append( last );
|
||||||
|
} else newExceptions.append( *iter );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
model().set( newExceptions );
|
||||||
|
|
||||||
|
// restore selection
|
||||||
|
m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ), QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
|
||||||
|
for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter )
|
||||||
|
{ m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); }
|
||||||
|
|
||||||
|
setChanged( true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::down()
|
||||||
|
{
|
||||||
|
|
||||||
|
InternalSettingsList selection( model().get( m_ui.exceptionListView->selectionModel()->selectedRows() ) );
|
||||||
|
if( selection.empty() )
|
||||||
|
{ return; }
|
||||||
|
|
||||||
|
// retrieve selected indexes in list and store in model
|
||||||
|
QModelIndexList selectedIndices( m_ui.exceptionListView->selectionModel()->selectedIndexes() );
|
||||||
|
InternalSettingsList selectedExceptions( model().get( selectedIndices ) );
|
||||||
|
|
||||||
|
InternalSettingsList currentExceptions( model().get() );
|
||||||
|
InternalSettingsList newExceptions;
|
||||||
|
|
||||||
|
InternalSettingsListIterator iter( currentExceptions );
|
||||||
|
iter.toBack();
|
||||||
|
while( iter.hasPrevious() )
|
||||||
|
{
|
||||||
|
|
||||||
|
InternalSettingsPtr current( iter.previous() );
|
||||||
|
|
||||||
|
// check if new list is not empty, current index is selected and last index is not.
|
||||||
|
// if yes, move.
|
||||||
|
if(
|
||||||
|
!( newExceptions.empty() ||
|
||||||
|
selectedIndices.indexOf( model().index( current ) ) == -1 ||
|
||||||
|
selectedIndices.indexOf( model().index( newExceptions.front() ) ) != -1
|
||||||
|
) )
|
||||||
|
{
|
||||||
|
|
||||||
|
InternalSettingsPtr first( newExceptions.front() );
|
||||||
|
newExceptions.removeFirst();
|
||||||
|
newExceptions.prepend( current );
|
||||||
|
newExceptions.prepend( first );
|
||||||
|
|
||||||
|
} else newExceptions.prepend( current );
|
||||||
|
}
|
||||||
|
|
||||||
|
model().set( newExceptions );
|
||||||
|
|
||||||
|
// restore selection
|
||||||
|
m_ui.exceptionListView->selectionModel()->select( model().index( selectedExceptions.front() ), QItemSelectionModel::Clear|QItemSelectionModel::Select|QItemSelectionModel::Rows );
|
||||||
|
for( InternalSettingsList::const_iterator iter = selectedExceptions.constBegin(); iter != selectedExceptions.constEnd(); ++iter )
|
||||||
|
{ m_ui.exceptionListView->selectionModel()->select( model().index( *iter ), QItemSelectionModel::Select|QItemSelectionModel::Rows ); }
|
||||||
|
|
||||||
|
setChanged( true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
void ExceptionListWidget::resizeColumns() const
|
||||||
|
{
|
||||||
|
m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnEnabled );
|
||||||
|
m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnType );
|
||||||
|
m_ui.exceptionListView->resizeColumnToContents( ExceptionModel::ColumnRegExp );
|
||||||
|
}
|
||||||
|
|
||||||
|
//_______________________________________________________
|
||||||
|
bool ExceptionListWidget::checkException( InternalSettingsPtr exception )
|
||||||
|
{
|
||||||
|
|
||||||
|
while( exception->exceptionPattern().isEmpty() || !QRegExp( exception->exceptionPattern() ).isValid() )
|
||||||
|
{
|
||||||
|
|
||||||
|
QMessageBox::warning( this, i18n( "Warning - Breeze Settings" ), i18n("Regular Expression syntax is incorrect") );
|
||||||
|
QPointer<ExceptionDialog> dialog( new ExceptionDialog( this ) );
|
||||||
|
dialog->setException( exception );
|
||||||
|
if( dialog->exec() == QDialog::Rejected )
|
||||||
|
{
|
||||||
|
delete dialog;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dialog->save();
|
||||||
|
delete dialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
124
config/breezeexceptionlistwidget.h
Normal file
124
config/breezeexceptionlistwidget.h
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
#ifndef breezeexceptionlistwidget_h
|
||||||
|
#define breezeexceptionlistwidget_h
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptionlistwidget.h
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "ui_breezeexceptionlistwidget.h"
|
||||||
|
#include "breezeexceptionmodel.h"
|
||||||
|
|
||||||
|
//* QDialog used to commit selected files
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
class ExceptionListWidget: public QWidget
|
||||||
|
{
|
||||||
|
|
||||||
|
//* Qt meta object
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit ExceptionListWidget( QWidget* = nullptr );
|
||||||
|
|
||||||
|
//* set exceptions
|
||||||
|
void setExceptions( const InternalSettingsList& );
|
||||||
|
|
||||||
|
//* get exceptions
|
||||||
|
InternalSettingsList exceptions();
|
||||||
|
|
||||||
|
//* true if changed
|
||||||
|
virtual bool isChanged() const
|
||||||
|
{ return m_changed; }
|
||||||
|
|
||||||
|
Q_SIGNALS:
|
||||||
|
|
||||||
|
//* emitted when changed
|
||||||
|
void changed( bool );
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* model
|
||||||
|
const ExceptionModel& model() const
|
||||||
|
{ return m_model; }
|
||||||
|
|
||||||
|
//* model
|
||||||
|
ExceptionModel& model()
|
||||||
|
{ return m_model; }
|
||||||
|
|
||||||
|
protected Q_SLOTS:
|
||||||
|
|
||||||
|
//* update button states
|
||||||
|
virtual void updateButtons();
|
||||||
|
|
||||||
|
//* add
|
||||||
|
virtual void add();
|
||||||
|
|
||||||
|
//* edit
|
||||||
|
virtual void edit();
|
||||||
|
|
||||||
|
//* remove
|
||||||
|
virtual void remove();
|
||||||
|
|
||||||
|
//* toggle
|
||||||
|
virtual void toggle( const QModelIndex& );
|
||||||
|
|
||||||
|
//* move up
|
||||||
|
virtual void up();
|
||||||
|
|
||||||
|
//* move down
|
||||||
|
virtual void down();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* resize columns
|
||||||
|
void resizeColumns() const;
|
||||||
|
|
||||||
|
//* check exception
|
||||||
|
bool checkException( InternalSettingsPtr );
|
||||||
|
|
||||||
|
//* set changed state
|
||||||
|
virtual void setChanged( bool value )
|
||||||
|
{
|
||||||
|
m_changed = value;
|
||||||
|
emit changed( value );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* model
|
||||||
|
ExceptionModel m_model;
|
||||||
|
|
||||||
|
//* ui
|
||||||
|
Ui_BreezeExceptionListWidget m_ui;
|
||||||
|
|
||||||
|
//* changed state
|
||||||
|
bool m_changed = false;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
107
config/breezeexceptionmodel.cpp
Normal file
107
config/breezeexceptionmodel.cpp
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptionmodel.cpp
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeexceptionmodel.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//_______________________________________________
|
||||||
|
const QString ExceptionModel::m_columnTitles[ ExceptionModel::nColumns ] =
|
||||||
|
{
|
||||||
|
QStringLiteral( "" ),
|
||||||
|
i18n("Exception Type"),
|
||||||
|
i18n("Regular Expression")
|
||||||
|
};
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
QVariant ExceptionModel::data( const QModelIndex& index, int role ) const
|
||||||
|
{
|
||||||
|
|
||||||
|
// check index, role and column
|
||||||
|
if( !index.isValid() ) return QVariant();
|
||||||
|
|
||||||
|
// retrieve associated file info
|
||||||
|
const InternalSettingsPtr& configuration( get(index) );
|
||||||
|
|
||||||
|
// return text associated to file and column
|
||||||
|
if( role == Qt::DisplayRole )
|
||||||
|
{
|
||||||
|
|
||||||
|
switch( index.column() )
|
||||||
|
{
|
||||||
|
case ColumnType:
|
||||||
|
{
|
||||||
|
switch( configuration->exceptionType() )
|
||||||
|
{
|
||||||
|
|
||||||
|
case InternalSettings::ExceptionWindowTitle:
|
||||||
|
return i18n( "Window Title" );
|
||||||
|
|
||||||
|
default:
|
||||||
|
case InternalSettings::ExceptionWindowClassName:
|
||||||
|
return i18n( "Window Class Name" );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
case ColumnRegExp: return configuration->exceptionPattern();
|
||||||
|
default: return QVariant();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if( role == Qt::CheckStateRole && index.column() == ColumnEnabled ) {
|
||||||
|
|
||||||
|
return configuration->enabled() ? Qt::Checked : Qt::Unchecked;
|
||||||
|
|
||||||
|
} else if( role == Qt::ToolTipRole && index.column() == ColumnEnabled ) {
|
||||||
|
|
||||||
|
return i18n("Enable/disable this exception");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return QVariant();
|
||||||
|
}
|
||||||
|
|
||||||
|
//__________________________________________________________________
|
||||||
|
QVariant ExceptionModel::headerData(int section, Qt::Orientation orientation, int role) const
|
||||||
|
{
|
||||||
|
|
||||||
|
if(
|
||||||
|
orientation == Qt::Horizontal &&
|
||||||
|
role == Qt::DisplayRole &&
|
||||||
|
section >= 0 &&
|
||||||
|
section < nColumns )
|
||||||
|
{ return m_columnTitles[section]; }
|
||||||
|
|
||||||
|
// return empty
|
||||||
|
return QVariant();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
81
config/breezeexceptionmodel.h
Normal file
81
config/breezeexceptionmodel.h
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
#ifndef breezeexceptionmodel_h
|
||||||
|
#define breezeexceptionmodel_h
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// breezeexceptionmodel.h
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezelistmodel.h"
|
||||||
|
#include "breezesettings.h"
|
||||||
|
#include "breeze.h"
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//* qlistview for object counters
|
||||||
|
class ExceptionModel: public ListModel<InternalSettingsPtr>
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* number of columns
|
||||||
|
enum { nColumns = 3 };
|
||||||
|
|
||||||
|
//* column type enumeration
|
||||||
|
enum ColumnType {
|
||||||
|
ColumnEnabled,
|
||||||
|
ColumnType,
|
||||||
|
ColumnRegExp
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
//*@name methods reimplemented from base class
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//* return data for a given index
|
||||||
|
QVariant data(const QModelIndex &index, int role) const override;
|
||||||
|
|
||||||
|
//* header data
|
||||||
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||||
|
|
||||||
|
//* number of columns for a given index
|
||||||
|
int columnCount(const QModelIndex& ) const override
|
||||||
|
{ return nColumns; }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* sort
|
||||||
|
void privateSort( int, Qt::SortOrder ) override
|
||||||
|
{}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* column titles
|
||||||
|
static const QString m_columnTitles[ nColumns ];
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
68
config/breezeitemmodel.cpp
Normal file
68
config/breezeitemmodel.cpp
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// itemmodel.cpp
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeitemmodel.h"
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//_______________________________________________________________
|
||||||
|
ItemModel::ItemModel( QObject* parent ):
|
||||||
|
QAbstractItemModel( parent )
|
||||||
|
{}
|
||||||
|
|
||||||
|
//____________________________________________________________
|
||||||
|
void ItemModel::sort( int column, Qt::SortOrder order )
|
||||||
|
{
|
||||||
|
|
||||||
|
// store column and order
|
||||||
|
m_sortColumn = column;
|
||||||
|
m_sortOrder = order;
|
||||||
|
|
||||||
|
// emit signals and call private methods
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
privateSort( column, order );
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//____________________________________________________________
|
||||||
|
QModelIndexList ItemModel::indexes( int column, const QModelIndex& parent ) const
|
||||||
|
{
|
||||||
|
QModelIndexList out;
|
||||||
|
int rows( rowCount( parent ) );
|
||||||
|
for( int row = 0; row < rows; row++ )
|
||||||
|
{
|
||||||
|
QModelIndex index( this->index( row, column, parent ) );
|
||||||
|
if( !index.isValid() ) continue;
|
||||||
|
out.append( index );
|
||||||
|
out += indexes( column, index );
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
113
config/breezeitemmodel.h
Normal file
113
config/breezeitemmodel.h
Normal file
|
@ -0,0 +1,113 @@
|
||||||
|
#ifndef ItemModel_h
|
||||||
|
#define ItemModel_h
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// itemmodel.h
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009-2010 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include <QAbstractItemModel>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
//* Job model. Stores job information for display in lists
|
||||||
|
class ItemModel : public QAbstractItemModel
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit ItemModel(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
//* destructor
|
||||||
|
virtual ~ItemModel()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//* return all indexes in model starting from parent [recursive]
|
||||||
|
QModelIndexList indexes( int column = 0, const QModelIndex& parent = QModelIndex() ) const;
|
||||||
|
|
||||||
|
//*@name sorting
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//* sort
|
||||||
|
virtual void sort()
|
||||||
|
{ sort( sortColumn(), sortOrder() ); }
|
||||||
|
|
||||||
|
//* sort
|
||||||
|
void sort( int column, Qt::SortOrder order = Qt::AscendingOrder ) override;
|
||||||
|
|
||||||
|
//* current sorting column
|
||||||
|
const int& sortColumn() const
|
||||||
|
{ return m_sortColumn; }
|
||||||
|
|
||||||
|
//* current sort order
|
||||||
|
const Qt::SortOrder& sortOrder() const
|
||||||
|
{ return m_sortOrder; }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* this sort columns without calling the layout changed callbacks
|
||||||
|
void privateSort()
|
||||||
|
{ privateSort( m_sortColumn, m_sortOrder ); }
|
||||||
|
|
||||||
|
//* private sort, with no signals emmitted
|
||||||
|
virtual void privateSort( int column, Qt::SortOrder order ) = 0;
|
||||||
|
|
||||||
|
//* used to sort items in list
|
||||||
|
class SortFTor
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//* constructor
|
||||||
|
explicit SortFTor( const int& type, Qt::SortOrder order = Qt::AscendingOrder ):
|
||||||
|
_type( type ),
|
||||||
|
_order( order )
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//* column
|
||||||
|
int _type;
|
||||||
|
|
||||||
|
//* order
|
||||||
|
Qt::SortOrder _order;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//* sorting column
|
||||||
|
int m_sortColumn = 0;
|
||||||
|
|
||||||
|
//* sorting order
|
||||||
|
Qt::SortOrder m_sortOrder = Qt::AscendingOrder;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
365
config/breezelistmodel.h
Normal file
365
config/breezelistmodel.h
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
#ifndef ListModel_h
|
||||||
|
#define ListModel_h
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
// listmodel.h
|
||||||
|
// -------------------
|
||||||
|
//
|
||||||
|
// Copyright (c) 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr>
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
// of this software and associated documentation files (the "Software"), to
|
||||||
|
// deal in the Software without restriction, including without limitation the
|
||||||
|
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
// sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
// furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||||
|
// IN THE SOFTWARE.
|
||||||
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#include "breezeitemmodel.h"
|
||||||
|
|
||||||
|
#include <QSet>
|
||||||
|
#include <QList>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
//! Job model. Stores job information for display in lists
|
||||||
|
template<class T> class ListModel : public ItemModel
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
//! value type
|
||||||
|
typedef T ValueType;
|
||||||
|
|
||||||
|
//! reference
|
||||||
|
typedef T& Reference;
|
||||||
|
|
||||||
|
//! pointer
|
||||||
|
typedef T* Pointer;
|
||||||
|
|
||||||
|
//! value list and iterators
|
||||||
|
typedef QList<ValueType> List;
|
||||||
|
typedef QListIterator<ValueType> ListIterator;
|
||||||
|
typedef QMutableListIterator<ValueType> MutableListIterator;
|
||||||
|
|
||||||
|
//! list of vector
|
||||||
|
// typedef QSet<ValueType> Set;
|
||||||
|
|
||||||
|
//! constructor
|
||||||
|
ListModel(QObject *parent = nullptr):
|
||||||
|
ItemModel( parent )
|
||||||
|
{}
|
||||||
|
|
||||||
|
//! destructor
|
||||||
|
virtual ~ListModel()
|
||||||
|
{}
|
||||||
|
|
||||||
|
//!@name methods reimplemented from base class
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! flags
|
||||||
|
Qt::ItemFlags flags(const QModelIndex &index) const override
|
||||||
|
{
|
||||||
|
if (!index.isValid()) return nullptr;
|
||||||
|
return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! unique index for given row, column and parent index
|
||||||
|
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if index is valid
|
||||||
|
if( !hasIndex( row, column, parent ) ) return QModelIndex();
|
||||||
|
|
||||||
|
// return invalid index if parent is valid
|
||||||
|
if( parent.isValid() ) return QModelIndex();
|
||||||
|
|
||||||
|
// check against _values
|
||||||
|
return ( row < (int) _values.size() ) ? createIndex( row, column ):QModelIndex();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! index of parent
|
||||||
|
QModelIndex parent(const QModelIndex &) const override
|
||||||
|
{ return QModelIndex(); }
|
||||||
|
|
||||||
|
//! number of rows below given index
|
||||||
|
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||||
|
{ return parent.isValid() ? 0:_values.size(); }
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//!@name selection
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! clear internal list selected items
|
||||||
|
virtual void clearSelectedIndexes()
|
||||||
|
{ _selection.clear(); }
|
||||||
|
|
||||||
|
//! store index internal selection state
|
||||||
|
virtual void setIndexSelected( const QModelIndex& index, bool value )
|
||||||
|
{
|
||||||
|
if( value ) _selection.push_back( get(index) );
|
||||||
|
else _selection.erase( std::remove( _selection.begin(), _selection.end(), get(index) ), _selection.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! get list of internal selected items
|
||||||
|
virtual QModelIndexList selectedIndexes() const
|
||||||
|
{
|
||||||
|
|
||||||
|
QModelIndexList out;
|
||||||
|
for( typename List::const_iterator iter = _selection.begin(); iter != _selection.end(); iter++ )
|
||||||
|
{
|
||||||
|
QModelIndex index( ListModel::index( *iter ) );
|
||||||
|
if( index.isValid() ) out.push_back( index );
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//!@name interface
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! add value
|
||||||
|
virtual void add( const ValueType& value )
|
||||||
|
{
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
_add( value );
|
||||||
|
privateSort();
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! add values
|
||||||
|
virtual void add( const List& values )
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if not empty
|
||||||
|
// this avoids sending useless signals
|
||||||
|
if( values.empty() ) return;
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
|
||||||
|
for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ )
|
||||||
|
{ _add( *iter ); }
|
||||||
|
|
||||||
|
privateSort();
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! insert values
|
||||||
|
virtual void insert( const QModelIndex& index, const ValueType& value )
|
||||||
|
{
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
_insert( index, value );
|
||||||
|
emit layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! insert values
|
||||||
|
virtual void insert( const QModelIndex& index, const List& values )
|
||||||
|
{
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
|
||||||
|
// need to loop in reverse order so that the "values" ordering is preserved
|
||||||
|
ListIterator iter( values );
|
||||||
|
iter.toBack();
|
||||||
|
while( iter.hasPrevious() )
|
||||||
|
{ _insert( index, iter.previous() ); }
|
||||||
|
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! insert values
|
||||||
|
virtual void replace( const QModelIndex& index, const ValueType& value )
|
||||||
|
{
|
||||||
|
if( !index.isValid() ) add( value );
|
||||||
|
else {
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
setIndexSelected( index, false );
|
||||||
|
_values[index.row()] = value;
|
||||||
|
setIndexSelected( index, true );
|
||||||
|
emit layoutChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//! remove
|
||||||
|
virtual void remove( const ValueType& value )
|
||||||
|
{
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
_remove( value );
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! remove
|
||||||
|
virtual void remove( const List& values )
|
||||||
|
{
|
||||||
|
|
||||||
|
// check if not empty
|
||||||
|
// this avoids sending useless signals
|
||||||
|
if( values.empty() ) return;
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
for( typename List::const_iterator iter = values.begin(); iter != values.end(); iter++ )
|
||||||
|
{ _remove( *iter ); }
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! clear
|
||||||
|
virtual void clear()
|
||||||
|
{ set( List() ); }
|
||||||
|
|
||||||
|
//! update values from list
|
||||||
|
/*!
|
||||||
|
values that are not found in current are removed
|
||||||
|
new values are set to the end.
|
||||||
|
This is slower than the "set" method, but the selection is not cleared in the process
|
||||||
|
*/
|
||||||
|
virtual void update( List values )
|
||||||
|
{
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
|
||||||
|
// store values to be removed
|
||||||
|
List removed_values;
|
||||||
|
|
||||||
|
// update values that are common to both lists
|
||||||
|
for( typename List::iterator iter = _values.begin(); iter != _values.end(); iter++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
// see if iterator is in list
|
||||||
|
typename List::iterator found_iter( std::find( values.begin(), values.end(), *iter ) );
|
||||||
|
if( found_iter == values.end() ) removed_values.push_back( *iter );
|
||||||
|
else {
|
||||||
|
*iter = *found_iter;
|
||||||
|
values.erase( found_iter );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove values that have not been found in new list
|
||||||
|
for( typename List::const_iterator iter = removed_values.constBegin(); iter != removed_values.constEnd(); iter++ )
|
||||||
|
{ _remove( *iter ); }
|
||||||
|
|
||||||
|
// add remaining values
|
||||||
|
for( typename List::const_iterator iter = values.constBegin(); iter != values.constEnd(); iter++ )
|
||||||
|
{ _add( *iter ); }
|
||||||
|
|
||||||
|
privateSort();
|
||||||
|
emit layoutChanged();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//! set all values
|
||||||
|
virtual void set( const List& values )
|
||||||
|
{
|
||||||
|
|
||||||
|
emit layoutAboutToBeChanged();
|
||||||
|
_values = values;
|
||||||
|
_selection.clear();
|
||||||
|
privateSort();
|
||||||
|
emit layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
//! return all values
|
||||||
|
const List& get() const
|
||||||
|
{ return _values; }
|
||||||
|
|
||||||
|
//! return value for given index
|
||||||
|
virtual ValueType get( const QModelIndex& index ) const
|
||||||
|
{ return (index.isValid() && index.row() < int(_values.size()) ) ? _values[index.row()]:ValueType(); }
|
||||||
|
|
||||||
|
//! return value for given index
|
||||||
|
virtual ValueType& get( const QModelIndex& index )
|
||||||
|
{
|
||||||
|
Q_ASSERT( index.isValid() && index.row() < int( _values.size() ) );
|
||||||
|
return _values[index.row()];
|
||||||
|
}
|
||||||
|
|
||||||
|
//! return all values
|
||||||
|
List get( const QModelIndexList& indexes ) const
|
||||||
|
{
|
||||||
|
List out;
|
||||||
|
for( QModelIndexList::const_iterator iter = indexes.begin(); iter != indexes.end(); iter++ )
|
||||||
|
{ if( iter->isValid() && iter->row() < int(_values.size()) ) out.push_back( get( *iter ) ); }
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! return index associated to a given value
|
||||||
|
virtual QModelIndex index( const ValueType& value, int column = 0 ) const
|
||||||
|
{
|
||||||
|
for( int row = 0; row < _values.size(); ++row )
|
||||||
|
{ if( value == _values[row] ) return index( row, column ); }
|
||||||
|
return QModelIndex();
|
||||||
|
}
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
//! return true if model contains given index
|
||||||
|
virtual bool contains( const QModelIndex& index ) const
|
||||||
|
{ return index.isValid() && index.row() < _values.size(); }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
//! return all values
|
||||||
|
List& _get()
|
||||||
|
{ return _values; }
|
||||||
|
|
||||||
|
//! add, without update
|
||||||
|
virtual void _add( const ValueType& value )
|
||||||
|
{
|
||||||
|
typename List::iterator iter = std::find( _values.begin(), _values.end(), value );
|
||||||
|
if( iter == _values.end() ) _values.push_back( value );
|
||||||
|
else *iter = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! add, without update
|
||||||
|
virtual void _insert( const QModelIndex& index, const ValueType& value )
|
||||||
|
{
|
||||||
|
if( !index.isValid() ) add( value );
|
||||||
|
int row = 0;
|
||||||
|
typename List::iterator iter( _values.begin() );
|
||||||
|
for( ;iter != _values.end() && row != index.row(); iter++, row++ )
|
||||||
|
{}
|
||||||
|
|
||||||
|
_values.insert( iter, value );
|
||||||
|
}
|
||||||
|
|
||||||
|
//! remove, without update
|
||||||
|
virtual void _remove( const ValueType& value )
|
||||||
|
{
|
||||||
|
_values.erase( std::remove( _values.begin(), _values.end(), value ), _values.end() );
|
||||||
|
_selection.erase( std::remove( _selection.begin(), _selection.end(), value ), _selection.end() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
//! values
|
||||||
|
List _values;
|
||||||
|
|
||||||
|
//! selection
|
||||||
|
List _selection;
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
552
config/ui/breezeconfigurationui.ui
Normal file
552
config/ui/breezeconfigurationui.ui
Normal file
|
@ -0,0 +1,552 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BreezeConfigurationUI</class>
|
||||||
|
<widget class="QWidget" name="BreezeConfigurationUI">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>428</width>
|
||||||
|
<height>418</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<property name="margin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="tabWidget">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="tab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>General</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_4">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>Tit&le alignment:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>titleAlignment</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="titleAlignment">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Left</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Center</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Center (Full Width)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Right</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<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>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_4">
|
||||||
|
<property name="text">
|
||||||
|
<string>B&utton size:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>buttonSize</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QComboBox" name="buttonSize">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Tiny</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Small</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Medium</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Large</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Very Large</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="3">
|
||||||
|
<widget class="QCheckBox" name="drawBorderOnMaximizedWindows">
|
||||||
|
<property name="text">
|
||||||
|
<string>Allow resizing maximized windows from window edges</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0" colspan="3">
|
||||||
|
<widget class="QCheckBox" name="drawSizeGrip">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add handle to resize windows with no border</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="8" column="0" colspan="3">
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,0,0,1">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_6">
|
||||||
|
<property name="text">
|
||||||
|
<string>Opacity:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QSpinBox" name="opacitySpinBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string> %</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<spacer name="horizontalSpacer_6">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>5</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="3">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Font:</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0" colspan="5">
|
||||||
|
<widget class="QFontComboBox" name="fontComboBox"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" alignment="Qt::AlignLeft">
|
||||||
|
<widget class="QSpinBox" name="fontSizeSpinBox">
|
||||||
|
<property name="minimum">
|
||||||
|
<number>5</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>50</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_9">
|
||||||
|
<property name="text">
|
||||||
|
<string>Size:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4">
|
||||||
|
<spacer name="horizontalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>5</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string>Weight:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QComboBox" name="weightComboBox">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Normal</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Medium</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>DemiBold</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Bold</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>ExtraBold</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Black</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<widget class="QCheckBox" name="italicCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Italic</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3">
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>5</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item row="9" column="0" colspan="3">
|
||||||
|
<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>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_2">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Animations</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_5">
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="animationsDurationLabel">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Anima&tions duration:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>animationsDuration</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSpinBox" name="animationsDuration">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="suffix">
|
||||||
|
<string> ms</string>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>500</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<spacer name="horizontalSpacer_4">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0" colspan="3">
|
||||||
|
<widget class="QCheckBox" name="animationsEnabled">
|
||||||
|
<property name="text">
|
||||||
|
<string>Enable animations</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0" colspan="3">
|
||||||
|
<spacer name="verticalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_4">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Shadows</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Si&ze:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>shadowSize</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="shadowSize">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">None</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Small</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Medium</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Large</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Button size:">Very Large</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string comment="strength of the shadow (from transparent to opaque)">S&trength:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>shadowStrength</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QSpinBox" name="shadowStrength">
|
||||||
|
<property name="suffix">
|
||||||
|
<string>%</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>10</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<spacer name="horizontalSpacer_5">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Color:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="KColorButton" name="shadowColor"/>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="3">
|
||||||
|
<spacer name="verticalSpacer_3">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<widget class="QWidget" name="tab_3">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Window-Specific Overrides</string>
|
||||||
|
</attribute>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="Breeze::ExceptionListWidget" name="exceptions" native="true">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<customwidgets>
|
||||||
|
<customwidget>
|
||||||
|
<class>KColorButton</class>
|
||||||
|
<extends>QPushButton</extends>
|
||||||
|
<header>kcolorbutton.h</header>
|
||||||
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>Breeze::ExceptionListWidget</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>config/breezeexceptionlistwidget.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
|
</customwidgets>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>tabWidget</tabstop>
|
||||||
|
<tabstop>titleAlignment</tabstop>
|
||||||
|
<tabstop>buttonSize</tabstop>
|
||||||
|
<tabstop>drawBorderOnMaximizedWindows</tabstop>
|
||||||
|
<tabstop>drawSizeGrip</tabstop>
|
||||||
|
<tabstop>animationsEnabled</tabstop>
|
||||||
|
<tabstop>animationsDuration</tabstop>
|
||||||
|
<tabstop>shadowSize</tabstop>
|
||||||
|
<tabstop>shadowStrength</tabstop>
|
||||||
|
<tabstop>shadowColor</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>animationsEnabled</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>animationsDurationLabel</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>34</x>
|
||||||
|
<y>194</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>84</x>
|
||||||
|
<y>221</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>animationsEnabled</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>animationsDuration</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>108</x>
|
||||||
|
<y>194</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>141</x>
|
||||||
|
<y>229</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
146
config/ui/breezedetectwidget.ui
Normal file
146
config/ui/breezedetectwidget.ui
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BreezeDetectWidget</class>
|
||||||
|
<widget class="QDialog" name="BreezeDetectWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>400</width>
|
||||||
|
<height>239</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Information about Selected Window</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>Class: </string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="windowClass">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Title: </string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="windowTitle">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">TextLabel</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Window Property Selection</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="windowClassCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Use window class (whole application)</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QRadioButton" name="windowTitleCheckBox">
|
||||||
|
<property name="locale">
|
||||||
|
<locale language="French" country="France"/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Use window title</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</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>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>BreezeDetectWidget</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>BreezeDetectWidget</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
333
config/ui/breezeexceptiondialog.ui
Normal file
333
config/ui/breezeexceptiondialog.ui
Normal file
|
@ -0,0 +1,333 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BreezeExceptionDialog</class>
|
||||||
|
<widget class="QDialog" name="BreezeExceptionDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>362</width>
|
||||||
|
<height>321</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Dialog</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Window Identification</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_2">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>&Matching window property: </string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>exceptionType</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Regular expression &to match: </string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="buddy">
|
||||||
|
<cstring>exceptionEditor</cstring>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QPushButton" name="detectDialogButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Detect Window Properties</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="exceptionEditor">
|
||||||
|
<property name="showClearButton" stdset="0">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" colspan="2">
|
||||||
|
<widget class="QComboBox" name="exceptionType">
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Window Class Name</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Window Title</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
|
<property name="title">
|
||||||
|
<string>Decoration Options</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout_3">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QCheckBox" name="borderSizeCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Border size:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QComboBox" name="borderSizeComboBox">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">No Border</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">No Side Borders</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Tiny</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Normal</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Large</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Very Large</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Huge</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Very Huge</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string comment="@item:inlistbox Border size:">Oversized</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QCheckBox" name="isDialog">
|
||||||
|
<property name="text">
|
||||||
|
<string>Only for dialogs</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="6" column="0" colspan="2">
|
||||||
|
<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 row="1" column="0">
|
||||||
|
<widget class="QCheckBox" name="hideTitleBar">
|
||||||
|
<property name="text">
|
||||||
|
<string>Hide window title bar</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QCheckBox" name="opaqueTitleBar">
|
||||||
|
<property name="text">
|
||||||
|
<string>Opaque title bar</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0" colspan="2">
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="horizontalSpacer_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Fixed</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>16</width>
|
||||||
|
<height>5</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="opacityOverrideLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string>Override opacity:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QSpinBox" name="opacityOverrideLabelSpinBox">
|
||||||
|
<property name="suffix">
|
||||||
|
<string>%</string>
|
||||||
|
</property>
|
||||||
|
<property name="minimum">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<number>100</number>
|
||||||
|
</property>
|
||||||
|
<property name="value">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</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>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>BreezeExceptionDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>252</x>
|
||||||
|
<y>342</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>BreezeExceptionDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>320</x>
|
||||||
|
<y>342</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>borderSizeCheckBox</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>borderSizeComboBox</receiver>
|
||||||
|
<slot>setEnabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>125</x>
|
||||||
|
<y>162</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>163</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>opaqueTitleBar</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>opacityOverrideLabel</receiver>
|
||||||
|
<slot>setDisabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>104</x>
|
||||||
|
<y>202</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>82</x>
|
||||||
|
<y>229</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>opaqueTitleBar</sender>
|
||||||
|
<signal>toggled(bool)</signal>
|
||||||
|
<receiver>opacityOverrideLabelSpinBox</receiver>
|
||||||
|
<slot>setDisabled(bool)</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>104</x>
|
||||||
|
<y>202</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>166</x>
|
||||||
|
<y>229</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
114
config/ui/breezeexceptionlistwidget.ui
Normal file
114
config/ui/breezeexceptionlistwidget.ui
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>BreezeExceptionListWidget</class>
|
||||||
|
<widget class="QWidget" name="BreezeExceptionListWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>473</width>
|
||||||
|
<height>182</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>0</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<property name="leftMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="topMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="rightMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<property name="bottomMargin">
|
||||||
|
<number>0</number>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0" rowspan="6">
|
||||||
|
<widget class="QTreeView" name="exceptionListView">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>100</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>1</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QPushButton" name="moveUpButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Move Up</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QPushButton" name="moveDownButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Move Down</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QPushButton" name="addButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Add</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QPushButton" name="removeButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Remove</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QPushButton" name="editButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<tabstops>
|
||||||
|
<tabstop>exceptionListView</tabstop>
|
||||||
|
<tabstop>moveUpButton</tabstop>
|
||||||
|
<tabstop>moveDownButton</tabstop>
|
||||||
|
<tabstop>addButton</tabstop>
|
||||||
|
<tabstop>removeButton</tabstop>
|
||||||
|
<tabstop>editButton</tabstop>
|
||||||
|
</tabstops>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
29
libbreezecommon/CMakeLists.txt
Normal file
29
libbreezecommon/CMakeLists.txt
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
################# dependencies #################
|
||||||
|
|
||||||
|
### Qt/KDE
|
||||||
|
find_package(Qt5 REQUIRED CONFIG COMPONENTS Widgets)
|
||||||
|
|
||||||
|
################# configuration #################
|
||||||
|
configure_file(config-breezecommon.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-breezecommon.h )
|
||||||
|
|
||||||
|
################# breezestyle target #################
|
||||||
|
set(breeze10common_LIB_SRCS
|
||||||
|
breezeboxshadowrenderer.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(breeze10common5 ${breeze10common_LIB_SRCS})
|
||||||
|
|
||||||
|
generate_export_header(breeze10common5
|
||||||
|
BASE_NAME breezecommon
|
||||||
|
EXPORT_FILE_NAME breezecommon_export.h)
|
||||||
|
|
||||||
|
target_link_libraries(breeze10common5
|
||||||
|
PUBLIC
|
||||||
|
Qt5::Core
|
||||||
|
Qt5::Gui)
|
||||||
|
|
||||||
|
set_target_properties(breeze10common5 PROPERTIES
|
||||||
|
VERSION ${PROJECT_VERSION}
|
||||||
|
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||||
|
|
||||||
|
install(TARGETS breeze10common5 ${INSTALL_TARGETS_DEFAULT_ARGS} LIBRARY NAMELINK_SKIP)
|
358
libbreezecommon/breezeboxshadowrenderer.cpp
Normal file
358
libbreezecommon/breezeboxshadowrenderer.cpp
Normal file
|
@ -0,0 +1,358 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Vlad Zagorodniy <vladzzag@gmail.com>
|
||||||
|
*
|
||||||
|
* The box blur implementation is based on AlphaBoxBlur from Firefox.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
// own
|
||||||
|
#include "breezeboxshadowrenderer.h"
|
||||||
|
|
||||||
|
// auto-generated
|
||||||
|
#include "config-breezecommon.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#include <QtMath>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
static inline int calculateBlurRadius(qreal stdDev)
|
||||||
|
{
|
||||||
|
// See https://www.w3.org/TR/SVG11/filters.html#feGaussianBlurElement
|
||||||
|
const qreal gaussianScaleFactor = (3.0 * qSqrt(2.0 * M_PI) / 4.0) * 1.5;
|
||||||
|
return qMax(2, qFloor(stdDev * gaussianScaleFactor + 0.5));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline qreal calculateBlurStdDev(int radius)
|
||||||
|
{
|
||||||
|
// See https://www.w3.org/TR/css-backgrounds-3/#shadow-blur
|
||||||
|
return radius * 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline QSize calculateBlurExtent(int radius)
|
||||||
|
{
|
||||||
|
const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius));
|
||||||
|
return QSize(blurRadius, blurRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BoxLobes
|
||||||
|
{
|
||||||
|
int left; ///< how many pixels sample to the left
|
||||||
|
int right; ///< how many pixels sample to the right
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Compute box filter parameters.
|
||||||
|
*
|
||||||
|
* @param radius The blur radius.
|
||||||
|
* @returns Parameters for three box filters.
|
||||||
|
**/
|
||||||
|
static QVector<BoxLobes> computeLobes(int radius)
|
||||||
|
{
|
||||||
|
const int blurRadius = calculateBlurRadius(calculateBlurStdDev(radius));
|
||||||
|
const int z = blurRadius / 3;
|
||||||
|
|
||||||
|
int major;
|
||||||
|
int minor;
|
||||||
|
int final;
|
||||||
|
|
||||||
|
switch (blurRadius % 3) {
|
||||||
|
case 0:
|
||||||
|
major = z;
|
||||||
|
minor = z;
|
||||||
|
final = z;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
major = z + 1;
|
||||||
|
minor = z;
|
||||||
|
final = z;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
major = z + 1;
|
||||||
|
minor = z;
|
||||||
|
final = z + 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
Q_UNREACHABLE();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_ASSERT(major + minor + final == blurRadius);
|
||||||
|
|
||||||
|
return {
|
||||||
|
{major, minor},
|
||||||
|
{minor, major},
|
||||||
|
{final, final}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process a row with a box filter.
|
||||||
|
*
|
||||||
|
* @param src The start of the row.
|
||||||
|
* @param dst The destination.
|
||||||
|
* @param width The width of the row, in pixels.
|
||||||
|
* @param horizontalStride The number of bytes from one alpha value to the
|
||||||
|
* next alpha value.
|
||||||
|
* @param verticalStride The number of bytes from one row to the next row.
|
||||||
|
* @param lobes Params of the box filter.
|
||||||
|
* @param transposeInput Whether the input is transposed.
|
||||||
|
* @param transposeOutput Whether the output should be transposed.
|
||||||
|
**/
|
||||||
|
static inline void boxBlurRowAlpha(const uint8_t *src, uint8_t *dst, int width, int horizontalStride,
|
||||||
|
int verticalStride, const BoxLobes &lobes, bool transposeInput,
|
||||||
|
bool transposeOutput)
|
||||||
|
{
|
||||||
|
const int inputStep = transposeInput ? verticalStride : horizontalStride;
|
||||||
|
const int outputStep = transposeOutput ? verticalStride : horizontalStride;
|
||||||
|
|
||||||
|
const int boxSize = lobes.left + 1 + lobes.right;
|
||||||
|
const int reciprocal = (1 << 24) / boxSize;
|
||||||
|
|
||||||
|
uint32_t alphaSum = (boxSize + 1) / 2;
|
||||||
|
|
||||||
|
const uint8_t *left = src;
|
||||||
|
const uint8_t *right = src;
|
||||||
|
uint8_t *out = dst;
|
||||||
|
|
||||||
|
const uint8_t firstValue = src[0];
|
||||||
|
const uint8_t lastValue = src[(width - 1) * inputStep];
|
||||||
|
|
||||||
|
alphaSum += firstValue * lobes.left;
|
||||||
|
|
||||||
|
const uint8_t *initEnd = src + (boxSize - lobes.left) * inputStep;
|
||||||
|
while (right < initEnd) {
|
||||||
|
alphaSum += *right;
|
||||||
|
right += inputStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *leftEnd = src + boxSize * inputStep;
|
||||||
|
while (right < leftEnd) {
|
||||||
|
*out = (alphaSum * reciprocal) >> 24;
|
||||||
|
alphaSum += *right - firstValue;
|
||||||
|
right += inputStep;
|
||||||
|
out += outputStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *centerEnd = src + width * inputStep;
|
||||||
|
while (right < centerEnd) {
|
||||||
|
*out = (alphaSum * reciprocal) >> 24;
|
||||||
|
alphaSum += *right - *left;
|
||||||
|
left += inputStep;
|
||||||
|
right += inputStep;
|
||||||
|
out += outputStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint8_t *rightEnd = dst + width * outputStep;
|
||||||
|
while (out < rightEnd) {
|
||||||
|
*out = (alphaSum * reciprocal) >> 24;
|
||||||
|
alphaSum += lastValue - *left;
|
||||||
|
left += inputStep;
|
||||||
|
out += outputStep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blur the alpha channel of a given image.
|
||||||
|
*
|
||||||
|
* @param image The input image.
|
||||||
|
* @param radius The blur radius.
|
||||||
|
* @param rect Specifies what part of the image to blur. If nothing is provided, then
|
||||||
|
* the whole alpha channel of the input image will be blurred.
|
||||||
|
**/
|
||||||
|
static inline void boxBlurAlpha(QImage &image, int radius, const QRect &rect = {})
|
||||||
|
{
|
||||||
|
if (radius < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const QVector<BoxLobes> lobes = computeLobes(radius);
|
||||||
|
|
||||||
|
const QRect blurRect = rect.isNull() ? image.rect() : rect;
|
||||||
|
|
||||||
|
const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3;
|
||||||
|
const int width = blurRect.width();
|
||||||
|
const int height = blurRect.height();
|
||||||
|
const int rowStride = image.bytesPerLine();
|
||||||
|
const int pixelStride = image.depth() >> 3;
|
||||||
|
|
||||||
|
const int bufferStride = qMax(width, height) * pixelStride;
|
||||||
|
QScopedPointer<uint8_t, QScopedPointerArrayDeleter<uint8_t> > buf(new uint8_t[2 * bufferStride]);
|
||||||
|
uint8_t *buf1 = buf.data();
|
||||||
|
uint8_t *buf2 = buf1 + bufferStride;
|
||||||
|
|
||||||
|
// Blur the image in horizontal direction.
|
||||||
|
for (int i = 0; i < height; ++i) {
|
||||||
|
uint8_t *row = image.scanLine(blurRect.y() + i) + blurRect.x() * pixelStride + alphaOffset;
|
||||||
|
boxBlurRowAlpha(row, buf1, width, pixelStride, rowStride, lobes[0], false, false);
|
||||||
|
boxBlurRowAlpha(buf1, buf2, width, pixelStride, rowStride, lobes[1], false, false);
|
||||||
|
boxBlurRowAlpha(buf2, row, width, pixelStride, rowStride, lobes[2], false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blur the image in vertical direction.
|
||||||
|
for (int i = 0; i < width; ++i) {
|
||||||
|
uint8_t *column = image.scanLine(blurRect.y()) + (blurRect.x() + i) * pixelStride + alphaOffset;
|
||||||
|
boxBlurRowAlpha(column, buf1, height, pixelStride, rowStride, lobes[0], true, false);
|
||||||
|
boxBlurRowAlpha(buf1, buf2, height, pixelStride, rowStride, lobes[1], false, false);
|
||||||
|
boxBlurRowAlpha(buf2, column, height, pixelStride, rowStride, lobes[2], false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void mirrorTopLeftQuadrant(QImage &image)
|
||||||
|
{
|
||||||
|
const int width = image.width();
|
||||||
|
const int height = image.height();
|
||||||
|
|
||||||
|
const int centerX = qCeil(width * 0.5);
|
||||||
|
const int centerY = qCeil(height * 0.5);
|
||||||
|
|
||||||
|
const int alphaOffset = QSysInfo::ByteOrder == QSysInfo::BigEndian ? 0 : 3;
|
||||||
|
const int stride = image.depth() >> 3;
|
||||||
|
|
||||||
|
for (int y = 0; y < centerY; ++y) {
|
||||||
|
uint8_t *in = image.scanLine(y) + alphaOffset;
|
||||||
|
uint8_t *out = in + (width - 1) * stride;
|
||||||
|
|
||||||
|
for (int x = 0; x < centerX; ++x, in += stride, out -= stride) {
|
||||||
|
*out = *in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int y = 0; y < centerY; ++y) {
|
||||||
|
const uint8_t *in = image.scanLine(y) + alphaOffset;
|
||||||
|
uint8_t *out = image.scanLine(width - y - 1) + alphaOffset;
|
||||||
|
|
||||||
|
for (int x = 0; x < width; ++x, in += stride, out += stride) {
|
||||||
|
*out = *in;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void renderShadow(QPainter *painter, const QRect &rect, qreal borderRadius, const QPoint &offset, int radius, const QColor &color)
|
||||||
|
{
|
||||||
|
const QSize inflation = calculateBlurExtent(radius);
|
||||||
|
const QSize size = rect.size() + 2 * inflation;
|
||||||
|
|
||||||
|
const qreal dpr = painter->device()->devicePixelRatioF();
|
||||||
|
|
||||||
|
QImage shadow(size * dpr, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
shadow.setDevicePixelRatio(dpr);
|
||||||
|
shadow.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QRect boxRect(QPoint(0, 0), rect.size());
|
||||||
|
boxRect.moveCenter(QRect(QPoint(0, 0), size).center());
|
||||||
|
|
||||||
|
const qreal xRadius = 2.0 * borderRadius / boxRect.width();
|
||||||
|
const qreal yRadius = 2.0 * borderRadius / boxRect.height();
|
||||||
|
|
||||||
|
QPainter shadowPainter;
|
||||||
|
shadowPainter.begin(&shadow);
|
||||||
|
shadowPainter.setRenderHint(QPainter::Antialiasing);
|
||||||
|
shadowPainter.setPen(Qt::NoPen);
|
||||||
|
shadowPainter.setBrush(Qt::black);
|
||||||
|
shadowPainter.drawRoundedRect(boxRect, xRadius, yRadius);
|
||||||
|
shadowPainter.end();
|
||||||
|
|
||||||
|
// Because the shadow texture is symmetrical, that's enough to blur
|
||||||
|
// only the top-left quadrant and then mirror it.
|
||||||
|
const QRect blurRect(0, 0, qCeil(shadow.width() * 0.5), qCeil(shadow.height() * 0.5));
|
||||||
|
const int scaledRadius = qRound(radius * dpr);
|
||||||
|
boxBlurAlpha(shadow, scaledRadius, blurRect);
|
||||||
|
mirrorTopLeftQuadrant(shadow);
|
||||||
|
|
||||||
|
// Give the shadow a tint of the desired color.
|
||||||
|
shadowPainter.begin(&shadow);
|
||||||
|
shadowPainter.setCompositionMode(QPainter::CompositionMode_SourceIn);
|
||||||
|
shadowPainter.fillRect(shadow.rect(), color);
|
||||||
|
shadowPainter.end();
|
||||||
|
|
||||||
|
// Actually, present the shadow.
|
||||||
|
QRect shadowRect = shadow.rect();
|
||||||
|
shadowRect.setSize(shadowRect.size() / dpr);
|
||||||
|
shadowRect.moveCenter(rect.center() + offset);
|
||||||
|
painter->drawImage(shadowRect, shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowRenderer::setBoxSize(const QSize &size)
|
||||||
|
{
|
||||||
|
m_boxSize = size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowRenderer::setBorderRadius(qreal radius)
|
||||||
|
{
|
||||||
|
m_borderRadius = radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowRenderer::setDevicePixelRatio(qreal dpr)
|
||||||
|
{
|
||||||
|
m_dpr = dpr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowRenderer::addShadow(const QPoint &offset, int radius, const QColor &color)
|
||||||
|
{
|
||||||
|
Shadow shadow = {};
|
||||||
|
shadow.offset = offset;
|
||||||
|
shadow.radius = radius;
|
||||||
|
shadow.color = color;
|
||||||
|
m_shadows.append(shadow);
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage BoxShadowRenderer::render() const
|
||||||
|
{
|
||||||
|
if (m_shadows.isEmpty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize canvasSize;
|
||||||
|
for (const Shadow &shadow : qAsConst(m_shadows)) {
|
||||||
|
canvasSize = canvasSize.expandedTo(
|
||||||
|
calculateMinimumShadowTextureSize(m_boxSize, shadow.radius, shadow.offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
QImage canvas(canvasSize * m_dpr, QImage::Format_ARGB32_Premultiplied);
|
||||||
|
canvas.setDevicePixelRatio(m_dpr);
|
||||||
|
canvas.fill(Qt::transparent);
|
||||||
|
|
||||||
|
QRect boxRect(QPoint(0, 0), m_boxSize);
|
||||||
|
boxRect.moveCenter(QRect(QPoint(0, 0), canvasSize).center());
|
||||||
|
|
||||||
|
QPainter painter(&canvas);
|
||||||
|
for (const Shadow &shadow : qAsConst(m_shadows)) {
|
||||||
|
renderShadow(&painter, boxRect, m_borderRadius, shadow.offset, shadow.radius, shadow.color);
|
||||||
|
}
|
||||||
|
painter.end();
|
||||||
|
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize BoxShadowRenderer::calculateMinimumBoxSize(int radius)
|
||||||
|
{
|
||||||
|
const QSize blurExtent = calculateBlurExtent(radius);
|
||||||
|
return 2 * blurExtent + QSize(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
QSize BoxShadowRenderer::calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset)
|
||||||
|
{
|
||||||
|
return boxSize + 2 * calculateBlurExtent(radius) + QSize(qAbs(offset.x()), qAbs(offset.y()));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Breeze
|
105
libbreezecommon/breezeboxshadowrenderer.h
Normal file
105
libbreezecommon/breezeboxshadowrenderer.h
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2018 Vlad Zagorodniy <vladzzag@gmail.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, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// own
|
||||||
|
#include "breezecommon_export.h"
|
||||||
|
|
||||||
|
// Qt
|
||||||
|
#include <QColor>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QPoint>
|
||||||
|
#include <QSize>
|
||||||
|
|
||||||
|
namespace Breeze
|
||||||
|
{
|
||||||
|
|
||||||
|
class BREEZECOMMON_EXPORT BoxShadowRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
// Compiler generated constructors & destructor are fine.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the size of the box.
|
||||||
|
* @param size The size of the box.
|
||||||
|
**/
|
||||||
|
void setBoxSize(const QSize &size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the radius of box' corners.
|
||||||
|
* @param radius The border radius, in pixels.
|
||||||
|
**/
|
||||||
|
void setBorderRadius(qreal radius);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the device pixel ratio of the resulting shadow texture.
|
||||||
|
* @param dpr The device pixel ratio.
|
||||||
|
**/
|
||||||
|
void setDevicePixelRatio(qreal dpr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a shadow.
|
||||||
|
* @param offset The offset of the shadow.
|
||||||
|
* @param radius The blur radius.
|
||||||
|
* @param color The color of the shadow.
|
||||||
|
**/
|
||||||
|
void addShadow(const QPoint &offset, int radius, const QColor &color);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render the shadow.
|
||||||
|
**/
|
||||||
|
QImage render() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the minimum size of the box.
|
||||||
|
*
|
||||||
|
* This helper computes the minimum size of the box so the shadow behind it has
|
||||||
|
* full its strength.
|
||||||
|
*
|
||||||
|
* @param radius The blur radius of the shadow.
|
||||||
|
**/
|
||||||
|
static QSize calculateMinimumBoxSize(int radius);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate the minimum size of the shadow texture.
|
||||||
|
*
|
||||||
|
* This helper computes the minimum size of the resulting texture so the shadow
|
||||||
|
* is not clipped.
|
||||||
|
*
|
||||||
|
* @param boxSize The size of the box.
|
||||||
|
* @param radius The blur radius.
|
||||||
|
* @param offset The offset of the shadow.
|
||||||
|
**/
|
||||||
|
static QSize calculateMinimumShadowTextureSize(const QSize &boxSize, int radius, const QPoint &offset);
|
||||||
|
|
||||||
|
private:
|
||||||
|
QSize m_boxSize;
|
||||||
|
qreal m_borderRadius = 0.0;
|
||||||
|
qreal m_dpr = 1.0;
|
||||||
|
|
||||||
|
struct Shadow {
|
||||||
|
QPoint offset;
|
||||||
|
int radius;
|
||||||
|
QColor color;
|
||||||
|
};
|
||||||
|
|
||||||
|
QVector<Shadow> m_shadows;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Breeze
|
28
libbreezecommon/config-breezecommon.h.cmake
Normal file
28
libbreezecommon/config-breezecommon.h.cmake
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
/* config-breezecommon.h. Generated by cmake from config-breezecommon.h.cmake */
|
||||||
|
|
||||||
|
/*************************************************************************
|
||||||
|
* Copyright (C) 2014 by Hugo Pereira Da Costa <hugo.pereira@free.fr> *
|
||||||
|
* *
|
||||||
|
* This program is free software; you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program; if not, write to the *
|
||||||
|
* Free Software Foundation, Inc., *
|
||||||
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . *
|
||||||
|
*************************************************************************/
|
||||||
|
|
||||||
|
#ifndef config_breeze_common_h
|
||||||
|
#define config_breeze_common_h
|
||||||
|
|
||||||
|
/* Define to 1 if breeze is compiled against KDE4 */
|
||||||
|
#cmakedefine01 BREEZE_COMMON_USE_KDE4
|
||||||
|
|
||||||
|
#endif
|
BIN
screenshots/Desktop.png
Normal file
BIN
screenshots/Desktop.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 899 KiB |
BIN
screenshots/Settings.png
Normal file
BIN
screenshots/Settings.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Loading…
Add table
Add a link
Reference in a new issue