aboutsummaryrefslogtreecommitdiff
path: root/src-qt5/core/lumina-theme-engine
diff options
context:
space:
mode:
authorWeblate <noreply@weblate.org>2017-07-19 18:57:55 +0000
committerWeblate <noreply@weblate.org>2017-07-19 18:57:55 +0000
commit72e16f90563b4998a71feed573140041f2db8fc3 (patch)
treecc9418321d40d2fa187c6b48e174cea360f7fd27 /src-qt5/core/lumina-theme-engine
parentTranslated using Weblate (Czech) (diff)
parentMerge branch 'master' of github.com:trueos/lumina (diff)
downloadlumina-72e16f90563b4998a71feed573140041f2db8fc3.tar.gz
lumina-72e16f90563b4998a71feed573140041f2db8fc3.tar.bz2
lumina-72e16f90563b4998a71feed573140041f2db8fc3.zip
Merge branch 'master' of github.com:trueos/lumina
Diffstat (limited to 'src-qt5/core/lumina-theme-engine')
-rw-r--r--src-qt5/core/lumina-theme-engine/LICENSE38
-rw-r--r--src-qt5/core/lumina-theme-engine/README.md14
-rw-r--r--src-qt5/core/lumina-theme-engine/lthemeengine.pri32
-rw-r--r--src-qt5/core/lumina-theme-engine/lthemeengine.pro57
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine-qtplugin.pro35
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine.json3
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp366
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.h122
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/main.cpp52
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine-style.pro26
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine.json3
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.cpp63
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.h50
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine-style/plugin.cpp57
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.cpp418
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.h79
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.ui243
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.cpp138
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.h56
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.ui160
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.cpp126
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.h62
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.ui134
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.cpp214
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.h57
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.ui51
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.cpp140
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.h54
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.ui327
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp132
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.desktop9
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.h60
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.pro55
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/main.cpp84
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.cpp90
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.h57
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.ui47
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.cpp146
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.h68
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.ui120
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/previewform.ui76
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.cpp85
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.h59
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.ui47
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp232
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.h66
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.ui84
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.cpp33
-rw-r--r--src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.h43
49 files changed, 4770 insertions, 0 deletions
diff --git a/src-qt5/core/lumina-theme-engine/LICENSE b/src-qt5/core/lumina-theme-engine/LICENSE
new file mode 100644
index 00000000..2179b01c
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/LICENSE
@@ -0,0 +1,38 @@
+Copyright for original source of project (prior to commit a852d14 of:
+https://github.com/trueos/lumina/tree/master/src-qt5/core/lumina-theme-engine
+held by Ilya Kotov <forkotov02@hotmail.ru> https://sourceforge.net/projects/qt5ct/
+under an MIT License.
+Original AUTHORS : https://sourceforge.net/p/qt5ct/code/HEAD/tree/trunk/qt5ct/AUTHORS
+
+All further commits are Copyright of q5sys under MIT License.
+
+
+Original Project Copyright:
+
+
+Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src-qt5/core/lumina-theme-engine/README.md b/src-qt5/core/lumina-theme-engine/README.md
new file mode 100644
index 00000000..d46797b1
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/README.md
@@ -0,0 +1,14 @@
+## Lumina Theme Engine
+
+This is a theme engine for the Lumina Desktop
+
+### Dependencies
+
+1. Qt 5.4+
+ - qtbase >= 5.4.0
+ - qtsvg >= 5.4.0
+ - qttools >= 5.4.0
+
+2. Lumina Desktop
+
+Environment Variable QT_QPA_PLATFORMTHEME=lthemeengine needs to be set
diff --git a/src-qt5/core/lumina-theme-engine/lthemeengine.pri b/src-qt5/core/lumina-theme-engine/lthemeengine.pri
new file mode 100644
index 00000000..be67734b
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/lthemeengine.pri
@@ -0,0 +1,32 @@
+#Some conf to redirect intermediate stuff in separate dirs
+UI_DIR=./.build/ui/
+MOC_DIR=./.build/moc/
+OBJECTS_DIR=./.build/obj
+RCC_DIR=./.build/rcc
+
+QMAKE_DISTCLEAN += -r .build
+
+CONFIG += c++11
+
+!isEqual (QT_MAJOR_VERSION, 5) {
+ error("Use Qt 5.4.0 or higher.")
+}
+
+!greaterThan(QT_MINOR_VERSION, 3) {
+ error("Use Qt 5.4.0 or higher.")
+}
+
+#Install paths
+unix {
+ isEmpty(PREFIX) {
+ PREFIX = /usr
+ }
+ isEmpty(PLUGINDIR) {
+ PLUGINDIR = $$[QT_INSTALL_PLUGINS]
+ }
+
+ BINDIR = $$PREFIX/bin
+ DATADIR = $$PREFIX/share
+
+ DEFINES += LTHEMEENGINE_DATADIR=\\\"$$DATADIR\\\"
+}
diff --git a/src-qt5/core/lumina-theme-engine/lthemeengine.pro b/src-qt5/core/lumina-theme-engine/lthemeengine.pro
new file mode 100644
index 00000000..d8ba709e
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/lthemeengine.pro
@@ -0,0 +1,57 @@
+QT += core gui
+greaterThan(QT_MAJOR_VERSION, 4): QT += widgets x11extras network
+
+QMAKE_DISTCLEAN += -r .build
+
+CONFIG += c++11
+
+desktop.files=src/lthemeengine/ltheme.desktop
+desktop.path=$${L_SHAREDIR}/applications/
+
+#Install paths
+unix {
+ isEmpty(PREFIX) {
+ PREFIX = /usr
+ }
+ isEmpty(PLUGINDIR) {
+ PLUGINDIR = $$[QT_INSTALL_PLUGINS]
+ }
+
+ BINDIR = $$PREFIX/bin
+ DATADIR = $$PREFIX/share
+
+ DEFINES += LTHEMEENGINE_DATADIR=\\\"$$DATADIR\\\"
+}
+
+TEMPLATE = subdirs
+
+SUBDIRS += src/lthemeengine-qtplugin src/lthemeengine-style src/lthemeengine
+
+unix:exists($$[QT_INSTALL_BINS]/lrelease){
+LRELEASE_EXECUTABLE = $$[QT_INSTALL_BINS]/lrelease
+}
+
+unix:exists($$[QT_INSTALL_BINS]/lrelease-qt5){
+LRELEASE_EXECUTABLE = $$[QT_INSTALL_BINS]/lrelease-qt5
+}
+
+
+isEmpty(LRELEASE_EXECUTABLE){
+error(Could not find lrelease executable)
+}
+else {
+message(Found lrelease executable: $$LRELEASE_EXECUTABLE)
+}
+
+message (PREFIX=$$PREFIX)
+message (BINDIR=$$BINDIR)
+message (DATADIR=$$DATADIR)
+message (PLUGINDIR=$$PLUGINDIR)
+equals (DISABLE_WIDGETS,1):message ("QtWidgets are disabled!")
+
+#Some conf to redirect intermediate stuff in separate dirs
+UI_DIR=./.build/ui/
+MOC_DIR=./.build/moc/
+OBJECTS_DIR=./.build/obj
+RCC_DIR=./.build/rcc
+
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine-qtplugin.pro b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine-qtplugin.pro
new file mode 100644
index 00000000..064c7642
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine-qtplugin.pro
@@ -0,0 +1,35 @@
+include(../../lthemeengine.pri)
+
+TEMPLATE = lib
+TARGET = lthemeengine
+CONFIG += plugin
+
+greaterThan(QT_MINOR_VERSION, 7) {
+ QT += gui-private theme_support-private
+} else {
+ QT += gui-private platformsupport-private
+}
+
+!contains(DEFINES, QT_NO_DBUS):greaterThan(QT_MINOR_VERSION, 5) {
+ QT += dbus
+}
+
+SOURCES += \
+ main.cpp \
+ lthemeengineplatformtheme.cpp \
+ ../lthemeengine/lthemeengine.cpp
+
+!equals (DISABLE_WIDGETS,1) {
+ QT += widgets
+}
+
+OTHER_FILES += lthemeengine.json
+
+INCLUDEPATH += ../
+
+HEADERS += \
+ lthemeengineplatformtheme.h \
+ ../lthemeengine/lthemeengine.h
+
+target.path = $$PLUGINDIR/platformthemes
+INSTALLS += target
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine.json b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine.json
new file mode 100644
index 00000000..433d4a88
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengine.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "lthemeengine" ]
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp
new file mode 100644
index 00000000..02f6a10f
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.cpp
@@ -0,0 +1,366 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QVariant>
+#include <QSettings>
+#include <QGuiApplication>
+#include <QScreen>
+#include <QFont>
+#include <QPalette>
+#include <QTimer>
+#include <QIcon>
+#include <QRegExp>
+#ifdef QT_WIDGETS_LIB
+#include <QStyle>
+#include <QStyleFactory>
+#include <QApplication>
+#include <QWidget>
+#endif
+#include <QFile>
+#include <QFileSystemWatcher>
+
+#include <lthemeengine/lthemeengine.h>
+#include "lthemeengineplatformtheme.h"
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) && !defined(QT_NO_DBUS)
+#include <private/qdbusmenubar_p.h>
+#endif
+#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
+#include <QDBusArgument>
+#include <private/qdbustrayicon_p.h>
+#endif
+
+
+
+Q_LOGGING_CATEGORY(llthemeengine, "lthemeengine")
+
+//QT_QPA_PLATFORMTHEME=lthemeengine
+
+lthemeenginePlatformTheme::lthemeenginePlatformTheme()
+{
+ if(QGuiApplication::desktopSettingsAware())
+ {
+ readSettings();
+ QMetaObject::invokeMethod(this, "applySettings", Qt::QueuedConnection);
+#ifdef QT_WIDGETS_LIB
+ QMetaObject::invokeMethod(this, "createFSWatcher", Qt::QueuedConnection);
+#endif
+ QGuiApplication::setFont(m_generalFont);
+ }
+ qCDebug(llthemeengine) << "using lthemeengine plugin";
+#ifdef QT_WIDGETS_LIB
+ if(!QStyleFactory::keys().contains("lthemeengine-style"))
+ qCCritical(llthemeengine) << "unable to find lthemeengine proxy style";
+#endif
+}
+
+lthemeenginePlatformTheme::~lthemeenginePlatformTheme()
+{
+ if(m_customPalette)
+ delete m_customPalette;
+}
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) && !defined(QT_NO_DBUS)
+QPlatformMenuBar *lthemeenginePlatformTheme::createPlatformMenuBar() const
+{
+ if(m_checkDBusGlobalMenu)
+ {
+ QDBusConnection conn = QDBusConnection::sessionBus();
+ m_dbusGlobalMenuAvailable = conn.interface()->isServiceRegistered("com.canonical.AppMenu.Registrar");
+ qCDebug(llthemeengine) << "D-Bus global menu:" << (m_dbusGlobalMenuAvailable ? "yes" : "no");
+ }
+ return (m_dbusGlobalMenuAvailable ? new QDBusMenuBar() : nullptr);
+}
+#endif
+
+#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
+QPlatformSystemTrayIcon *lthemeenginePlatformTheme::createPlatformSystemTrayIcon() const
+{
+ if(m_checkDBusTray)
+ {
+ QDBusMenuConnection conn;
+ m_dbusTrayAvailable = conn.isStatusNotifierHostRegistered();
+ m_checkDBusTray = false;
+ qCDebug(llthemeengine) << "D-Bus system tray:" << (m_dbusTrayAvailable ? "yes" : "no");
+ }
+ return (m_dbusTrayAvailable ? new QDBusTrayIcon() : nullptr);
+}
+#endif
+
+const QPalette *lthemeenginePlatformTheme::palette(QPlatformTheme::Palette type) const
+{
+ Q_UNUSED(type);
+ return (m_usePalette ? m_customPalette : nullptr);
+}
+
+const QFont *lthemeenginePlatformTheme::font(QPlatformTheme::Font type) const
+{
+ if(type == QPlatformTheme::FixedFont)
+ return &m_fixedFont;
+ return &m_generalFont;
+}
+
+QVariant lthemeenginePlatformTheme::themeHint(QPlatformTheme::ThemeHint hint) const
+{
+ switch (hint)
+ {
+ case QPlatformTheme::CursorFlashTime:
+ return m_cursorFlashTime;
+ case MouseDoubleClickInterval:
+ return m_doubleClickInterval;
+ case QPlatformTheme::ToolButtonStyle:
+ return m_toolButtonStyle;
+ case QPlatformTheme::SystemIconThemeName:
+ return m_iconTheme;
+ case QPlatformTheme::StyleNames:
+ return QStringList() << "lthemeengine-style";
+ case QPlatformTheme::IconThemeSearchPaths:
+ return lthemeengine::iconPaths();
+ case DialogButtonBoxLayout:
+ return m_buttonBoxLayout;
+ case QPlatformTheme::UiEffects:
+ return m_uiEffects;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+ case QPlatformTheme::WheelScrollLines:
+ return m_wheelScrollLines;
+#endif
+ default:
+ return QPlatformTheme::themeHint(hint);
+ }
+}
+
+void lthemeenginePlatformTheme::applySettings()
+{
+ if(!QGuiApplication::desktopSettingsAware())
+ return;
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 5, 0))
+ if(!m_update)
+ {
+ //do not override application palette
+ if(QCoreApplication::testAttribute(Qt::AA_SetPalette))
+ {
+ m_usePalette = false;
+ qCDebug(llthemeengine) << "palette support is disabled";
+ }
+ }
+#endif
+
+#ifdef QT_WIDGETS_LIB
+ if(hasWidgets())
+ {
+ qApp->setFont(m_generalFont);
+
+ //Qt 5.6 or higher should be use themeHint function on application startup.
+ //So, there is no need to call this function first time.
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+ if(m_update)
+ qApp->setWheelScrollLines(m_wheelScrollLines);
+#else
+ qApp->setWheelScrollLines(m_wheelScrollLines);
+#endif
+
+ if(m_update && qApp->style()->objectName() == "lthemeengine-style") //ignore application style
+ qApp->setStyle("lthemeengine-style"); //recreate style object
+
+ if(m_update && m_usePalette)
+ {
+ if(m_customPalette)
+ qApp->setPalette(*m_customPalette);
+ else
+ qApp->setPalette(qApp->style()->standardPalette());
+ }
+
+ //do not override application style
+ if(m_prevStyleSheet == qApp->styleSheet())
+ qApp->setStyleSheet(m_userStyleSheet);
+ else
+ qCDebug(llthemeengine) << "custom style sheet is disabled";
+ m_prevStyleSheet = m_userStyleSheet;
+ }
+#endif
+ QGuiApplication::setFont(m_generalFont); //apply font
+ QIcon::setThemeName(m_iconTheme); //apply icons
+ if(m_customPalette && m_usePalette)
+ QGuiApplication::setPalette(*m_customPalette); //apply palette
+
+#ifdef QT_WIDGETS_LIB
+ if(hasWidgets())
+ {
+ foreach (QWidget *w, qApp->allWidgets())
+ {
+ QEvent e(QEvent::ThemeChange);
+ QApplication::sendEvent(w, &e);
+ }
+ }
+#endif
+
+ if(!m_update)
+ m_update = true;
+}
+
+#ifdef QT_WIDGETS_LIB
+void lthemeenginePlatformTheme::createFSWatcher()
+{
+ QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
+ watcher->addPath(lthemeengine::configPath());
+
+ QTimer *timer = new QTimer(this);
+ timer->setSingleShot(true);
+ timer->setInterval(3000);
+ connect(watcher, SIGNAL(directoryChanged(QString)), timer, SLOT(start()));
+ connect(timer, SIGNAL(timeout()), SLOT(updateSettings()));
+}
+
+void lthemeenginePlatformTheme::updateSettings()
+{
+ qCDebug(llthemeengine) << "updating settings..";
+ readSettings();
+ applySettings();
+}
+#endif
+
+void lthemeenginePlatformTheme::readSettings()
+{
+ if(m_customPalette)
+ {
+ delete m_customPalette;
+ m_customPalette = 0;
+ }
+
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+
+ settings.beginGroup("Appearance");
+ m_style = settings.value("style", "Fusion").toString();
+ if(settings.value("custom_palette", false).toBool())
+ {
+ QString schemePath = settings.value("color_scheme_path").toString();
+ m_customPalette = new QPalette(loadColorScheme(schemePath));
+ }
+ m_iconTheme = settings.value("icon_theme").toString();
+ settings.endGroup();
+
+ settings.beginGroup("Fonts");
+ m_generalFont = settings.value("general", QPlatformTheme::font(QPlatformTheme::SystemFont)).value<QFont>();
+ m_fixedFont = settings.value("fixed", QPlatformTheme::font(QPlatformTheme::FixedFont)).value<QFont>();
+ settings.endGroup();
+
+ settings.beginGroup("Interface");
+ m_doubleClickInterval = QPlatformTheme::themeHint(QPlatformTheme::MouseDoubleClickInterval).toInt();
+ m_doubleClickInterval = settings.value("double_click_interval", m_doubleClickInterval).toInt();
+ m_cursorFlashTime = QPlatformTheme::themeHint(QPlatformTheme::CursorFlashTime).toInt();
+ m_cursorFlashTime = settings.value("cursor_flash_time", m_cursorFlashTime).toInt();
+ m_buttonBoxLayout = QPlatformTheme::themeHint(QPlatformTheme::DialogButtonBoxLayout).toInt();
+ m_buttonBoxLayout = settings.value("buttonbox_layout", m_buttonBoxLayout).toInt();
+ QCoreApplication::setAttribute(Qt::AA_DontShowIconsInMenus, !settings.value("menus_have_icons", true).toBool());
+ m_toolButtonStyle = settings.value("toolbutton_style", Qt::ToolButtonFollowStyle).toInt();
+ m_wheelScrollLines = settings.value("wheel_scroll_lines", 3).toInt();
+
+ //load effects
+ m_uiEffects = QPlatformTheme::themeHint(QPlatformTheme::UiEffects).toInt();
+ if(settings.childKeys().contains("gui_effects"))
+ {
+ QStringList effectList = settings.value("gui_effects").toStringList();
+ m_uiEffects = 0;
+ if(effectList.contains("General"))
+ m_uiEffects |= QPlatformTheme::GeneralUiEffect;
+ if(effectList.contains("AnimateMenu"))
+ m_uiEffects |= QPlatformTheme::AnimateMenuUiEffect;
+ if(effectList.contains("FadeMenu"))
+ m_uiEffects |= QPlatformTheme::FadeMenuUiEffect;
+ if(effectList.contains("AnimateCombo"))
+ m_uiEffects |= QPlatformTheme::AnimateComboUiEffect;
+ if(effectList.contains("AnimateTooltip"))
+ m_uiEffects |= QPlatformTheme::AnimateTooltipUiEffect;
+ if(effectList.contains("FadeTooltip"))
+ m_uiEffects |= QPlatformTheme::FadeTooltipUiEffect;
+ if(effectList.contains("AnimateToolBox"))
+ m_uiEffects |= QPlatformTheme::AnimateToolBoxUiEffect;
+ }
+
+ //load style sheets
+#ifdef QT_WIDGETS_LIB
+ QStringList qssPaths = settings.value("stylesheets").toStringList();
+ m_userStyleSheet = loadStyleSheets(qssPaths);
+#endif
+ settings.endGroup();
+}
+
+#ifdef QT_WIDGETS_LIB
+bool lthemeenginePlatformTheme::hasWidgets()
+{
+ return qobject_cast<QApplication *> (qApp) != nullptr;
+}
+#endif
+
+QString lthemeenginePlatformTheme::loadStyleSheets(const QStringList &paths)
+{
+ QString content;
+ foreach (QString path, paths)
+ {
+ if(!QFile::exists(path))
+ continue;
+
+ QFile file(path);
+ file.open(QIODevice::ReadOnly);
+ content.append(file.readAll());
+ }
+ QRegExp regExp("//.*(\\n|$)");
+ regExp.setMinimal(true);
+ content.remove(regExp);
+ return content;
+}
+
+QPalette lthemeenginePlatformTheme::loadColorScheme(const QString &filePath)
+{
+ QPalette customPalette;
+ QSettings settings(filePath, QSettings::IniFormat);
+ settings.beginGroup("ColorScheme");
+ QStringList activeColors = settings.value("active_colors").toStringList();
+ QStringList inactiveColors = settings.value("inactive_colors").toStringList();
+ QStringList disabledColors = settings.value("disabled_colors").toStringList();
+ settings.endGroup();
+
+ if(activeColors.count() == QPalette::NColorRoles &&
+ inactiveColors.count() == QPalette::NColorRoles &&
+ disabledColors.count() == QPalette::NColorRoles)
+ {
+ for (int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ QPalette::ColorRole role = QPalette::ColorRole(i);
+ customPalette.setColor(QPalette::Active, role, QColor(activeColors.at(i)));
+ customPalette.setColor(QPalette::Inactive, role, QColor(inactiveColors.at(i)));
+ customPalette.setColor(QPalette::Disabled, role, QColor(disabledColors.at(i)));
+ }
+ }
+ else
+ {
+ customPalette = *QPlatformTheme::palette(SystemPalette); //load fallback palette
+ }
+
+ return customPalette;
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.h
new file mode 100644
index 00000000..3996b451
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/lthemeengineplatformtheme.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LTHEMEENGINEPLATFORMTHEME_H
+#define LTHEMEENGINEPLATFORMTHEME_H
+
+#include <qpa/qplatformtheme.h>
+#include <QObject>
+#include <QFont>
+#include <QPalette>
+#include <QLoggingCategory>
+
+#if (QT_VERSION < QT_VERSION_CHECK(5, 5, 0))
+#ifndef QT_NO_SYSTEMTRAYICON
+#define QT_NO_SYSTEMTRAYICON
+#endif
+#endif
+
+class QPalette;
+#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
+class QPlatformSystemTrayIcon;
+#endif
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) && !defined(QT_NO_DBUS)
+class QPlatformMenuBar;
+#endif
+
+class lthemeenginePlatformTheme : public QObject, public QPlatformTheme
+{
+ Q_OBJECT
+public:
+ lthemeenginePlatformTheme();
+
+ virtual ~lthemeenginePlatformTheme();
+
+
+ //virtual QPlatformMenuItem* createPlatformMenuItem() const;
+ //virtual QPlatformMenu* createPlatformMenu() const;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) && !defined(QT_NO_DBUS)
+ virtual QPlatformMenuBar* createPlatformMenuBar() const;
+#endif
+ //virtual void showPlatformMenuBar() {}
+ //virtual bool usePlatformNativeDialog(DialogType type) const;
+ //virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
+#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
+ virtual QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const;
+#endif
+ virtual const QPalette *palette(Palette type = SystemPalette) const;
+ virtual const QFont *font(Font type = SystemFont) const;
+ virtual QVariant themeHint(ThemeHint hint) const;
+ //virtual QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const;
+ //virtual QPixmap fileIconPixmap(const QFileInfo &fileInfo, const QSizeF &size,
+ // QPlatformTheme::IconOptions iconOptions = 0) const;
+
+ //virtual QIconEngine *createIconEngine(const QString &iconName) const;
+ //virtual QList<QKeySequence> keyBindings(QKeySequence::StandardKey key) const;
+ //virtual QString standardButtonText(int button) const;
+
+private slots:
+ void applySettings();
+#ifdef QT_WIDGETS_LIB
+ void createFSWatcher();
+ void updateSettings();
+#endif
+
+private:
+ void readSettings();
+#ifdef QT_WIDGETS_LIB
+ bool hasWidgets();
+#endif
+ QString loadStyleSheets(const QStringList &paths);
+ QPalette loadColorScheme(const QString &filePath);
+ QString m_style, m_iconTheme, m_userStyleSheet, m_prevStyleSheet;
+ QPalette *m_customPalette = nullptr;
+ QFont m_generalFont, m_fixedFont;
+ int m_doubleClickInterval;
+ int m_cursorFlashTime;
+ int m_uiEffects;
+ int m_buttonBoxLayout;
+ bool m_update = false;
+ bool m_usePalette = true;
+ int m_toolButtonStyle = Qt::ToolButtonFollowStyle;
+ int m_wheelScrollLines = 3;
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) && !defined(QT_NO_DBUS)
+ mutable bool m_dbusGlobalMenuAvailable = false;
+ mutable bool m_checkDBusGlobalMenu = true;
+#endif
+#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
+ mutable bool m_dbusTrayAvailable = false;
+ mutable bool m_checkDBusTray = true;
+#endif
+
+};
+
+Q_DECLARE_LOGGING_CATEGORY(llthemeengine)
+
+#endif // LTHEMEENGINEPLATFORMTHEME_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/main.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/main.cpp
new file mode 100644
index 00000000..37798f70
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-qtplugin/main.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <qpa/qplatformthemeplugin.h>
+#include "lthemeengineplatformtheme.h"
+
+QT_BEGIN_NAMESPACE
+
+class lthemeenginePlatformThemePlugin: public QPlatformThemePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QPA.QPlatformThemeFactoryInterface.5.1" FILE "lthemeengine.json")
+public:
+ QPlatformTheme *create(const QString &key, const QStringList &params);
+};
+
+QPlatformTheme *lthemeenginePlatformThemePlugin::create(const QString &key, const QStringList &params)
+{
+ Q_UNUSED(params);
+ if (key.toLower() == "lthemeengine")
+ return new lthemeenginePlatformTheme();
+ return NULL;
+}
+
+QT_END_NAMESPACE
+
+#include "main.moc"
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine-style.pro b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine-style.pro
new file mode 100644
index 00000000..0b40de64
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine-style.pro
@@ -0,0 +1,26 @@
+include(../../lthemeengine.pri)
+
+TEMPLATE = lib
+TARGET = lthemeengine-style
+QT += widgets
+
+# Input
+
+CONFIG += plugin
+
+target.path = $$PLUGINDIR/styles
+INSTALLS += target
+
+INCLUDEPATH += ../
+
+HEADERS += \
+ lthemeengineproxystyle.h \
+ ../lthemeengine/lthemeengine.h
+
+SOURCES += \
+ plugin.cpp \
+ lthemeengineproxystyle.cpp \
+ ../lthemeengine/lthemeengine.cpp
+
+OTHER_FILES += \
+ lthemeengine.json
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine.json b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine.json
new file mode 100644
index 00000000..e8aae055
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengine.json
@@ -0,0 +1,3 @@
+{
+ "Keys": [ "lthemeengine-style" ]
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.cpp
new file mode 100644
index 00000000..c9833a30
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.cpp
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QSettings>
+#include <lthemeengine/lthemeengine.h>
+#include "lthemeengineproxystyle.h"
+
+lthemeengineProxyStyle::lthemeengineProxyStyle(const QString &key) :
+ QProxyStyle(key)
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ m_dialogButtonsHaveIcons = settings.value("Interface/dialog_buttons_have_icons", Qt::PartiallyChecked).toInt();
+ m_activateItemOnSingleClick = settings.value("Interface/activate_item_on_single_click", Qt::PartiallyChecked).toInt();
+}
+
+lthemeengineProxyStyle::~lthemeengineProxyStyle()
+{
+ //qDebug("%s", Q_FUNC_INFO);
+}
+
+int lthemeengineProxyStyle::styleHint(QStyle::StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const
+{
+ if(hint == QStyle::SH_DialogButtonBox_ButtonsHaveIcons)
+ {
+ if(m_dialogButtonsHaveIcons == Qt::Unchecked)
+ return 0;
+ else if(m_dialogButtonsHaveIcons == Qt::Checked)
+ return 1;
+ }
+ else if(hint == QStyle::QStyle::SH_ItemView_ActivateItemOnSingleClick)
+ {
+ if(m_activateItemOnSingleClick == Qt::Unchecked)
+ return 0;
+ else if(m_activateItemOnSingleClick == Qt::Checked)
+ return 1;
+ }
+ return QProxyStyle::styleHint(hint, option, widget, returnData);
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.h
new file mode 100644
index 00000000..47a18099
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/lthemeengineproxystyle.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LTHEMEENGINEPROXYSTYLE_H
+#define LTHEMEENGINEPROXYSTYLE_H
+
+#include <QProxyStyle>
+
+class lthemeengineProxyStyle : public QProxyStyle
+{
+ Q_OBJECT
+public:
+ explicit lthemeengineProxyStyle(const QString &key);
+
+ virtual ~lthemeengineProxyStyle();
+
+ int styleHint(StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const;
+
+private:
+ int m_dialogButtonsHaveIcons;
+ int m_activateItemOnSingleClick;
+
+};
+
+#endif // LTHEMEENGINEPROXYSTYLE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/plugin.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/plugin.cpp
new file mode 100644
index 00000000..9d63093e
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine-style/plugin.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QStylePlugin>
+#include <QSettings>
+#include <QStyleFactory>
+#include <lthemeengine/lthemeengine.h>
+#include "lthemeengineproxystyle.h"
+
+class lthemeengineStylePlugin : public QStylePlugin
+{
+ Q_OBJECT
+ Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "lthemeengine.json")
+
+public:
+ QStyle *create(const QString &key);
+};
+
+QStyle *lthemeengineStylePlugin::create(const QString &key)
+{
+ if (key == "lthemeengine-style")
+ {
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ QString style = settings.value("Appearance/style", "Fusion").toString();
+ if(key == style || !QStyleFactory::keys().contains(style))
+ style = "Fusion";
+ return new lthemeengineProxyStyle(style);
+ }
+ return 0;
+}
+
+#include "plugin.moc"
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.cpp
new file mode 100644
index 00000000..b9175d6e
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.cpp
@@ -0,0 +1,418 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QStyleFactory>
+#include <QMdiSubWindow>
+#include <QSettings>
+#include <QDir>
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QMenu>
+#include <QIcon>
+#include "lthemeengine.h"
+#include "appearancepage.h"
+#include "paletteeditdialog.h"
+#include "ui_appearancepage.h"
+#include "ui_previewform.h"
+
+AppearancePage::AppearancePage(QWidget *parent) :
+ TabPage(parent),
+ m_ui(new Ui::AppearancePage)
+{
+ m_ui->setupUi(this);
+ QStringList keys = QStyleFactory::keys();
+ keys.removeAll("lthemeengine-style"); //hide lthemeengine proxy style
+ m_ui->styleComboBox->addItems(keys);
+
+ connect(m_ui->paletteComboBox, SIGNAL(activated(int)), SLOT(updatePalette()));
+ connect(m_ui->customPaletteButton, SIGNAL(clicked()), SLOT(updatePalette()));
+ connect(m_ui->defaultPaletteButton, SIGNAL(clicked()), SLOT(updatePalette()));
+
+ m_previewWidget = new QWidget(this);
+ m_previewUi = new Ui::PreviewForm();
+ m_previewUi->setupUi(m_previewWidget);
+ QMdiSubWindow *w = m_ui->mdiArea->addSubWindow(m_previewWidget, Qt::CustomizeWindowHint
+ | Qt::WindowMinMaxButtonsHint
+ | Qt::WindowTitleHint);
+ w->move(10, 10);
+
+ QMenu *menu = new QMenu(this);
+ menu->addAction(QIcon::fromTheme("list-add"), tr("Create"), this, SLOT(createColorScheme()));
+ m_changeColorSchemeAction = menu->addAction(tr("Edit"), this, SLOT(changeColorScheme()));
+ menu->addAction(tr("Create a Copy"), this, SLOT(copyColorScheme()));
+ m_renameColorSchemeAction = menu->addAction(tr("Rename"), this, SLOT(renameColorScheme()));
+ menu->addSeparator();
+ m_removeColorSchemeAction = menu->addAction(tr("Remove"), this, SLOT(removeColorScheme()));
+ m_ui->colorSchemeButton->setMenu(menu);
+
+ m_changeColorSchemeAction->setIcon(QIcon::fromTheme("accessories-text-editor"));
+ m_removeColorSchemeAction->setIcon(QIcon::fromTheme("list-remove"));
+ connect(menu, SIGNAL(aboutToShow()), SLOT(updateActions()));
+
+ readSettings();
+}
+
+AppearancePage::~AppearancePage()
+{
+ if(m_selectedStyle)
+ delete m_selectedStyle;
+ delete m_ui;
+ delete m_previewUi;
+}
+
+void AppearancePage::writeSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Appearance");
+ settings.setValue("style", m_ui->styleComboBox->currentText());
+ settings.setValue("custom_palette", m_ui->customPaletteButton->isChecked());
+ settings.setValue("color_scheme_path", m_ui->colorSchemeComboBox->currentData().toString());
+ settings.endGroup();
+}
+
+void AppearancePage::on_styleComboBox_activated(const QString &text)
+{
+ QStyle *style = QStyleFactory::create(text);
+ if(!style)
+ return;
+ setStyle(m_previewWidget, style);
+
+ if(m_selectedStyle)
+ delete m_selectedStyle;
+ m_selectedStyle = style;
+
+ updatePalette();
+}
+
+void AppearancePage::on_colorSchemeComboBox_activated(int)
+{
+ m_customPalette = loadColorScheme(m_ui->colorSchemeComboBox->currentData().toString());
+ updatePalette();
+}
+
+void AppearancePage::createColorScheme()
+{
+ QString name = QInputDialog::getText(this, tr("Enter Color Scheme Name"), tr("File name:"));
+ if(name.isEmpty())
+ return;
+
+ if(!name.endsWith(".conf", Qt::CaseInsensitive))
+ name.append(".conf");
+
+ if(m_ui->colorSchemeComboBox->findText(name.section('.',0,0)) != -1)
+ {
+ QMessageBox::warning(this, tr("Error"), tr("The color scheme \"%1\" already exists")
+ .arg(name.section('.',0,0)));
+ return;
+ }
+
+ QString schemePath = lthemeengine::userColorSchemePath() + "/" + name;
+
+ createColorScheme(schemePath, palette());
+ m_ui->colorSchemeComboBox->addItem(name.section('.',0,0), schemePath);
+}
+
+void AppearancePage::changeColorScheme()
+{
+ if(m_ui->colorSchemeComboBox->currentIndex() < 0)
+ return;
+
+ if(!QFileInfo(m_ui->colorSchemeComboBox->currentData().toString()).isWritable())
+ {
+ QMessageBox::information(this, tr("Warning"), tr("The color scheme \"%1\" is read only")
+ .arg(m_ui->colorSchemeComboBox->currentText()));
+ return;
+ }
+
+ PaletteEditDialog d(m_customPalette, m_selectedStyle, this);
+ connect(&d, SIGNAL(paletteChanged(QPalette)), SLOT(setPreviewPalette(QPalette)));
+ if(d.exec() == QDialog::Accepted)
+ {
+ m_customPalette = d.selectedPalette();
+ createColorScheme(m_ui->colorSchemeComboBox->currentData().toString(), m_customPalette);
+ }
+ updatePalette();
+}
+
+void AppearancePage::removeColorScheme()
+{
+ int index = m_ui->colorSchemeComboBox->currentIndex();
+ if(index < 0 || m_ui->colorSchemeComboBox->count() <= 1)
+ return;
+
+ if(!QFileInfo(m_ui->colorSchemeComboBox->currentData().toString()).isWritable())
+ {
+ QMessageBox::information(this, tr("Warning"), tr("The color scheme \"%1\" is read only")
+ .arg(m_ui->colorSchemeComboBox->currentText()));
+ return;
+ }
+
+ int button = QMessageBox::question(this, tr("Confirm Remove"),
+ tr("Are you sure you want to remove color scheme \"%1\"?")
+ .arg(m_ui->colorSchemeComboBox->currentText()),
+ QMessageBox::Yes | QMessageBox::No);
+ if(button != QMessageBox::Yes)
+ return;
+
+ if(QFile::remove(m_ui->colorSchemeComboBox->currentData().toString()))
+ {
+ m_ui->colorSchemeComboBox->removeItem(index);
+ on_colorSchemeComboBox_activated(0);
+ }
+}
+
+void AppearancePage::copyColorScheme()
+{
+ if(m_ui->colorSchemeComboBox->currentIndex() < 0)
+ return;
+
+ QString name = QInputDialog::getText(this, tr("Enter Color Scheme Name"), tr("File name:"),
+ QLineEdit::Normal,
+ tr("%1 (copy)").arg(m_ui->colorSchemeComboBox->currentText()));
+ if(name.isEmpty() || name == m_ui->colorSchemeComboBox->currentText())
+ return;
+
+ if(!name.endsWith(".conf", Qt::CaseInsensitive))
+ name.append(".conf");
+
+ if(m_ui->colorSchemeComboBox->findText(name.section('.',0,0)) != -1)
+ {
+ QMessageBox::warning(this, tr("Error"), tr("The color scheme \"%1\" already exists")
+ .arg(name.section('.',0,0)));
+ return;
+ }
+
+ QString newPath = lthemeengine::userColorSchemePath() + "/" + name;
+ QFile::copy(m_ui->colorSchemeComboBox->currentData().toString(), newPath);
+ m_ui->colorSchemeComboBox->addItem(name.section('.',0,0), newPath);
+}
+
+void AppearancePage::renameColorScheme()
+{
+ int index = m_ui->colorSchemeComboBox->currentIndex();
+
+ if(index < 0)
+ return;
+
+ if(!QFileInfo(m_ui->colorSchemeComboBox->currentData().toString()).isWritable())
+ {
+ QMessageBox::information(this, tr("Warning"), tr("The color scheme \"%1\" is read only")
+ .arg(m_ui->colorSchemeComboBox->currentText()));
+ return;
+ }
+
+ QString name = QInputDialog::getText(this, tr("Enter Color Scheme Name"), tr("File name:"),
+ QLineEdit::Normal, m_ui->colorSchemeComboBox->currentText());
+ if(name.isEmpty() || name == m_ui->colorSchemeComboBox->currentText())
+ return;
+
+ if(!name.endsWith(".conf", Qt::CaseInsensitive))
+ name.append(".conf");
+
+ if(m_ui->colorSchemeComboBox->findText(name.section('.',0,0)) != -1)
+ {
+ QMessageBox::warning(this, tr("Error"), tr("The color scheme \"%1\" already exists")
+ .arg(name.section('.',0,0)));
+ return;
+ }
+
+ QString newPath = lthemeengine::userColorSchemePath() + "/" + name;
+ QFile::rename(m_ui->colorSchemeComboBox->currentData().toString(), newPath);
+ m_ui->colorSchemeComboBox->setItemText(index, name.section('.',0,0));
+ m_ui->colorSchemeComboBox->setItemData(index, newPath);
+}
+
+void AppearancePage::updatePalette()
+{
+ if(!m_selectedStyle)
+ return;
+
+ setPreviewPalette(m_ui->customPaletteButton->isChecked() ?
+ m_customPalette : m_selectedStyle->standardPalette());
+}
+
+void AppearancePage::setPreviewPalette(const QPalette &p)
+{
+ QPalette previewPalette = palette();
+
+ QPalette::ColorGroup colorGroup = QPalette::Disabled;
+
+ if(m_ui->paletteComboBox->currentIndex() == 0)
+ {
+ colorGroup = QPalette::Active;
+ }
+ else if(m_ui->paletteComboBox->currentIndex() == 1)
+ {
+ colorGroup = QPalette::Inactive;
+ }
+
+ for (int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ QPalette::ColorRole role = QPalette::ColorRole(i);
+ previewPalette.setColor(QPalette::Active, role, p.color(colorGroup, role));
+ previewPalette.setColor(QPalette::Inactive, role, p.color(colorGroup, role));
+ }
+
+ setPalette(m_ui->mdiArea, previewPalette);
+}
+
+void AppearancePage::updateActions()
+{
+ if(m_ui->colorSchemeComboBox->count() == 0 ||
+ !QFileInfo(m_ui->colorSchemeComboBox->currentData().toString()).isWritable())
+ {
+ m_changeColorSchemeAction->setVisible(false);
+ m_renameColorSchemeAction->setVisible(false);
+ m_removeColorSchemeAction->setVisible(false);
+ }
+ else
+ {
+ m_changeColorSchemeAction->setVisible(true);
+ m_renameColorSchemeAction->setVisible(true);
+ m_removeColorSchemeAction->setVisible(m_ui->colorSchemeComboBox->count() > 1);
+ }
+}
+
+void AppearancePage::readSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Appearance");
+ QString style = settings.value("style", "Fusion").toString();
+ m_ui->styleComboBox->setCurrentText(style);
+
+ m_ui->customPaletteButton->setChecked(settings.value("custom_palette", false).toBool());
+ QString colorSchemePath = settings.value("color_scheme_path").toString();
+
+ QDir("/").mkpath(lthemeengine::userColorSchemePath());
+ findColorSchemes(lthemeengine::userColorSchemePath());
+ findColorSchemes(lthemeengine::sharedColorSchemePath().join(", "));
+
+ if(m_ui->colorSchemeComboBox->count() == 0)
+ {
+ m_customPalette = palette(); //load fallback palette
+ }
+ else
+ {
+ int index = m_ui->colorSchemeComboBox->findData(colorSchemePath);
+ if(index >= 0)
+ m_ui->colorSchemeComboBox->setCurrentIndex(index);
+ m_customPalette = loadColorScheme(m_ui->colorSchemeComboBox->currentData().toString());
+ }
+
+ on_styleComboBox_activated(m_ui->styleComboBox->currentText());
+
+ settings.endGroup();
+}
+
+void AppearancePage::setStyle(QWidget *w, QStyle *s)
+{
+ foreach (QObject *o, w->children())
+ {
+ if(o->isWidgetType())
+ {
+ setStyle(qobject_cast<QWidget *>(o), s);
+ }
+ }
+ w->setStyle(s);
+}
+
+void AppearancePage::setPalette(QWidget *w, QPalette p)
+{
+ foreach (QObject *o, w->children())
+ {
+ if(o->isWidgetType())
+ {
+ setPalette(qobject_cast<QWidget *>(o), p);
+ }
+ }
+ w->setPalette(p);
+}
+
+void AppearancePage::findColorSchemes(const QString &path)
+{
+ QDir dir(path);
+ dir.setFilter(QDir::Files);
+ dir.setNameFilters(QStringList() << "*.conf");
+
+ foreach (QFileInfo info, dir.entryInfoList())
+ {
+ m_ui->colorSchemeComboBox->addItem(info.baseName(), info.filePath());
+ }
+}
+
+QPalette AppearancePage::loadColorScheme(const QString &filePath)
+{
+ QPalette customPalette;
+ QSettings settings(filePath, QSettings::IniFormat);
+ settings.beginGroup("ColorScheme");
+ QStringList activeColors = settings.value("active_colors").toStringList();
+ QStringList inactiveColors = settings.value("inactive_colors").toStringList();
+ QStringList disabledColors = settings.value("disabled_colors").toStringList();
+ settings.endGroup();
+
+ if(activeColors.count() == QPalette::NColorRoles &&
+ inactiveColors.count() == QPalette::NColorRoles &&
+ disabledColors.count() == QPalette::NColorRoles)
+ {
+ for (int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ QPalette::ColorRole role = QPalette::ColorRole(i);
+ customPalette.setColor(QPalette::Active, role, QColor(activeColors.at(i)));
+ customPalette.setColor(QPalette::Inactive, role, QColor(inactiveColors.at(i)));
+ customPalette.setColor(QPalette::Disabled, role, QColor(disabledColors.at(i)));
+ }
+ }
+ else
+ {
+ customPalette = palette(); //load fallback palette
+ }
+
+ return customPalette;
+}
+
+void AppearancePage::createColorScheme(const QString &name, const QPalette &palette)
+{
+ QSettings settings(name, QSettings::IniFormat);
+ settings.beginGroup("ColorScheme");
+
+ QStringList activeColors, inactiveColors, disabledColors;
+ for (int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ QPalette::ColorRole role = QPalette::ColorRole(i);
+ activeColors << palette.color(QPalette::Active, role).name();
+ inactiveColors << palette.color(QPalette::Inactive, role).name();
+ disabledColors << palette.color(QPalette::Disabled, role).name();
+ }
+
+ settings.setValue("active_colors",activeColors);
+ settings.setValue("inactive_colors",inactiveColors);
+ settings.setValue("disabled_colors",disabledColors);
+
+ settings.endGroup();
+
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.h
new file mode 100644
index 00000000..3a7752c7
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef APPEARANCEPAGE_H
+#define APPEARANCEPAGE_H
+
+#include "tabpage.h"
+
+namespace Ui {
+class AppearancePage;
+class PreviewForm;
+}
+
+class QStyle;
+class QAction;
+
+class AppearancePage : public TabPage
+{
+ Q_OBJECT
+
+public:
+ explicit AppearancePage(QWidget *parent = 0);
+ ~AppearancePage();
+
+ void writeSettings();
+
+private slots:
+ void on_styleComboBox_activated(const QString &text);
+ void on_colorSchemeComboBox_activated(int);
+ void createColorScheme();
+ void changeColorScheme();
+ void removeColorScheme();
+ void copyColorScheme();
+ void renameColorScheme();
+ void updatePalette();
+ void setPreviewPalette(const QPalette &p);
+ void updateActions();
+
+private:
+ void readSettings();
+ void setStyle(QWidget *w, QStyle *s);
+ void setPalette(QWidget *w, QPalette p);
+ void findColorSchemes(const QString &path);
+ QPalette loadColorScheme(const QString &filePath);
+ void createColorScheme(const QString &name, const QPalette &palette);
+ Ui::AppearancePage *m_ui;
+ QStyle *m_selectedStyle = nullptr;
+ QPalette m_customPalette;
+ QWidget *m_previewWidget;
+ QAction *m_changeColorSchemeAction, *m_renameColorSchemeAction, *m_removeColorSchemeAction;
+ Ui::PreviewForm *m_previewUi;
+};
+
+#endif // APPEARANCEPAGE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.ui
new file mode 100644
index 00000000..cd442930
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/appearancepage.ui
@@ -0,0 +1,243 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>AppearancePage</class>
+ <widget class="QWidget" name="AppearancePage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>596</width>
+ <height>470</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Style:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="3">
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Preview</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <widget class="QComboBox" name="paletteComboBox">
+ <item>
+ <property name="text">
+ <string>Active palette</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Inactive palette</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Disabled palette</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>82</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QMdiArea" name="mdiArea">
+ <property name="tabsMovable">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QComboBox" name="styleComboBox"/>
+ </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="2" column="0" colspan="3">
+ <widget class="QGroupBox" name="paletteGroupBox">
+ <property name="title">
+ <string>Palette</string>
+ </property>
+ <layout class="QVBoxLayout" name="_2">
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QRadioButton" name="defaultPaletteButton">
+ <property name="text">
+ <string>Default</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QRadioButton" name="customPaletteButton">
+ <property name="text">
+ <string>Custom</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>230</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QLabel" name="colorScheeLabel">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Color scheme:</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QComboBox" name="colorSchemeComboBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>150</width>
+ <height>0</height>
+ </size>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="colorSchemeButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::InstantPopup</enum>
+ </property>
+ <property name="arrowType">
+ <enum>Qt::NoArrow</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <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>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>customPaletteButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>colorScheeLabel</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>160</x>
+ <y>79</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>77</x>
+ <y>104</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>customPaletteButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>colorSchemeComboBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>144</x>
+ <y>75</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>146</x>
+ <y>100</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>customPaletteButton</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>colorSchemeButton</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>177</x>
+ <y>78</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>288</x>
+ <y>116</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.cpp
new file mode 100644
index 00000000..398a2436
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QXmlStreamWriter>
+#include <QFile>
+#include <QDir>
+#include <QMessageBox>
+#include "fontconfigdialog.h"
+#include "ui_fontconfigdialog.h"
+
+FontConfigDialog::FontConfigDialog(QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::FontConfigDialog)
+{
+ m_ui->setupUi(this);
+
+ m_ui->hintingStyleComboBox->addItem(tr("None"), "hintnone");
+ m_ui->hintingStyleComboBox->addItem(tr("Slight"), "hintslight");
+ m_ui->hintingStyleComboBox->addItem(tr("Medium"), "hintmedium");
+ m_ui->hintingStyleComboBox->addItem(tr("Full"), "hintfull");
+
+ m_ui->rgbaComboBox->addItem(tr("None"), "none");
+ m_ui->rgbaComboBox->addItem("rgb", "rgb");
+ m_ui->rgbaComboBox->addItem("bgr", "bgr");
+ m_ui->rgbaComboBox->addItem("vrgb", "vrgb");
+ m_ui->rgbaComboBox->addItem("vbgr", "vbgr");
+
+ m_ui->lcdFilterComboBox->addItem("lcdnone");
+ m_ui->lcdFilterComboBox->addItem("lcddefault");
+ m_ui->lcdFilterComboBox->addItem("lcdlight");
+ m_ui->lcdFilterComboBox->addItem("lcdlegacy");
+}
+
+FontConfigDialog::~FontConfigDialog()
+{
+ delete m_ui;
+}
+
+void FontConfigDialog::accept()
+{
+ QDir::home().mkpath(".config/fontconfig/");
+ QString path = QDir::homePath() + "/.config/fontconfig/fonts.conf";
+ qDebug("FontConfigDialog: fontconfig path: %s", qPrintable(path));
+
+
+ if(QFile::exists(path))
+ {
+ if(QMessageBox::question(this, tr("Font Configuration"),
+ tr("<i>%1</i> already exists. Do you want to replace it?").arg(path),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ {
+ QDialog::reject();
+ return;
+ }
+
+ QFile::remove(path + ".back");
+ QFile::copy(path, path + ".back");
+ }
+
+ QFile file(path);
+ if(!file.open(QIODevice::WriteOnly))
+ {
+ qWarning("FontConfigDialog: unable to open file: %s", qPrintable(file.errorString()));
+ return;
+ }
+
+ QXmlStreamWriter stream(&file);
+ stream.setAutoFormatting(true);
+
+ stream.writeStartDocument();
+ stream.writeDTD("<!DOCTYPE fontconfig SYSTEM \"fonts.dtd\">");
+ stream.writeStartElement("fontconfig");
+
+ stream.writeStartElement("match");
+ stream.writeAttribute("target", "font");
+ writeOption(&stream, "antialias", "bool", m_ui->antialisingCheckBox->isChecked() ? "true" : "false");
+ writeOption(&stream, "hinting", "bool", m_ui->hintingCheckBox->isChecked() ? "true" : "false");
+ writeOption(&stream, "hintstyle", "const", m_ui->hintingStyleComboBox->currentData().toString());
+ writeOption(&stream, "rgba", "const", m_ui->rgbaComboBox->currentData().toString());
+ writeOption(&stream, "autohint", "bool", m_ui->autohinterCheckBox->isChecked() ? "true" : "false");
+ writeOption(&stream, "lcdfilter", "const", m_ui->lcdFilterComboBox->currentText());
+ writeOption(&stream, "dpi", "double", QString::number(m_ui->dpiSpinBox->value()));
+ stream.writeEndElement();
+
+ if(m_ui->disableBoldAutohintCheckBox->isChecked())
+ {
+ stream.writeStartElement("match");
+ stream.writeAttribute("target", "font");
+
+ stream.writeStartElement("test");
+ stream.writeAttribute("name", "weight");
+ stream.writeAttribute("compare", "more");
+ stream.writeTextElement("const", "medium");
+ stream.writeEndElement();
+
+ writeOption(&stream, "autohint", "bool", m_ui->autohinterCheckBox->isChecked() ? "true" : "false");
+
+ stream.writeEndElement();
+ }
+ stream.writeEndElement();
+ stream.writeEndDocument();
+
+ QDialog::accept();
+}
+
+void FontConfigDialog::writeOption(QXmlStreamWriter *stream, const QString &name, const QString &type, const QString &value)
+{
+ stream->writeStartElement("edit");
+ stream->writeAttribute("name", name);
+ stream->writeAttribute("mode", "assign");
+ stream->writeTextElement(type, value);
+ stream->writeEndElement();
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.h
new file mode 100644
index 00000000..5b7e31a5
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FONTCONFIGDIALOG_H
+#define FONTCONFIGDIALOG_H
+
+#include <QDialog>
+
+namespace Ui {
+class FontConfigDialog;
+}
+
+class QXmlStreamWriter;
+
+class FontConfigDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit FontConfigDialog(QWidget *parent = 0);
+ ~FontConfigDialog();
+
+public slots:
+ void accept();
+ void writeOption(QXmlStreamWriter *stream, const QString &name, const QString &type, const QString &value);
+
+private:
+ Ui::FontConfigDialog *m_ui;
+};
+
+#endif // FONTCONFIGDIALOG_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.ui
new file mode 100644
index 00000000..a557695f
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontconfigdialog.ui
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FontConfigDialog</class>
+ <widget class="QDialog" name="FontConfigDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>349</width>
+ <height>286</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Font Configuration</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item row="5" column="0" colspan="2">
+ <widget class="QCheckBox" name="disableBoldAutohintCheckBox">
+ <property name="text">
+ <string>Disable automatic hinting for bold fonts</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>LCD filter:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="2">
+ <widget class="QCheckBox" name="autohinterCheckBox">
+ <property name="text">
+ <string>Automatic hinting</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2">
+ <widget class="QCheckBox" name="hintingCheckBox">
+ <property name="text">
+ <string>Hinting</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0" colspan="2">
+ <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>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>Font resolution:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QComboBox" name="lcdFilterComboBox"/>
+ </item>
+ <item row="3" column="1">
+ <widget class="QComboBox" name="rgbaComboBox"/>
+ </item>
+ <item row="2" column="1">
+ <widget class="QComboBox" name="hintingStyleComboBox"/>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Subpixel geometry:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="2">
+ <widget class="QCheckBox" name="antialisingCheckBox">
+ <property name="text">
+ <string>Antialiasing</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Hinting style:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QSpinBox" name="dpiSpinBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="suffix">
+ <string> dpi</string>
+ </property>
+ <property name="minimum">
+ <number>80</number>
+ </property>
+ <property name="maximum">
+ <number>180</number>
+ </property>
+ <property name="value">
+ <number>102</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>FontConfigDialog</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>FontConfigDialog</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>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.cpp
new file mode 100644
index 00000000..db48a3cc
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QSignalMapper>
+#include <QMessageBox>
+#include <QSettings>
+#include <QApplication>
+#include <QFontDialog>
+#include <QDir>
+#include <QFile>
+#include "lthemeengine.h"
+#include "fontspage.h"
+#include "fontconfigdialog.h"
+#include "ui_fontspage.h"
+
+FontsPage::FontsPage(QWidget *parent) :
+ TabPage(parent),
+ m_ui(new Ui::FontsPage)
+{
+ m_ui->setupUi(this);
+
+ QSignalMapper *mapper = new QSignalMapper(this);
+ mapper->setMapping(m_ui->changeGeneralFontButton, m_ui->generalFontLabel);
+ mapper->setMapping(m_ui->changeFixedWidthFontButton, m_ui->fixedFontLabel);
+ connect(m_ui->changeGeneralFontButton, SIGNAL(clicked()), mapper, SLOT(map()));
+ connect(m_ui->changeFixedWidthFontButton, SIGNAL(clicked()), mapper, SLOT(map()));
+ connect(mapper, SIGNAL(mapped(QWidget*)), SLOT(onFontChangeRequested(QWidget*)));
+
+ readSettings();
+
+ //icons
+ m_ui->createFontsConfButton->setIcon(QIcon::fromTheme("document-new"));
+ m_ui->removeFontsConfButton->setIcon(QIcon::fromTheme("edit-delete"));
+}
+
+FontsPage::~FontsPage()
+{
+ delete m_ui;
+}
+
+void FontsPage::writeSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Fonts");
+ settings.setValue("general", m_ui->generalFontLabel->font());
+ settings.setValue("fixed", m_ui->fixedFontLabel->font());
+ settings.endGroup();
+}
+
+void FontsPage::onFontChangeRequested(QWidget *widget)
+{
+ bool ok = false;
+ QFont font = QFontDialog::getFont (&ok, widget->font(), this);
+ if(ok)
+ {
+ widget->setFont(font);
+ qobject_cast<QLabel*>(widget)->setText(font.family () + " " + QString::number(font.pointSize ()));
+ }
+}
+
+void FontsPage::readSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Fonts");
+ loadFont(&settings, m_ui->generalFontLabel, "general");
+ loadFont(&settings, m_ui->fixedFontLabel, "fixed");
+ settings.endGroup();
+}
+
+void FontsPage::loadFont(QSettings *settings, QLabel *label, const QString &key)
+{
+ QFont font = settings->value(key, QApplication::font()).value<QFont>();
+ label->setText(font.family () + " " + QString::number(font.pointSize ()));
+ label->setFont(font);
+}
+
+void FontsPage::on_createFontsConfButton_clicked()
+{
+ FontConfigDialog d(this);
+ d.exec();
+}
+
+void FontsPage::on_removeFontsConfButton_clicked()
+{
+ QString path = QDir::homePath() + "/.config/fontconfig/fonts.conf";
+
+
+ if(QFile::exists(path))
+ {
+ if(QMessageBox::question(this, tr("Remove Font Configuration"),
+ tr("Are you sure you want to delete <i>%1</i>?").arg(path),
+ QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
+ {
+ return;
+ }
+
+ QFile::remove(path + ".back");
+ QFile::copy(path, path + ".back");
+ QFile::remove(path);
+ }
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.h
new file mode 100644
index 00000000..a9c5f1f6
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef FONTSPAGE_H
+#define FONTSPAGE_H
+
+#include "tabpage.h"
+
+namespace Ui {
+class FontsPage;
+}
+
+class QLabel;
+class QSettings;
+
+class FontsPage : public TabPage
+{
+ Q_OBJECT
+
+public:
+ explicit FontsPage(QWidget *parent = 0);
+ ~FontsPage();
+
+ void writeSettings();
+
+private slots:
+ void onFontChangeRequested(QWidget *widget);
+ void on_createFontsConfButton_clicked();
+ void on_removeFontsConfButton_clicked();
+
+private:
+ void readSettings();
+ void loadFont(QSettings *settings, QLabel *label, const QString &key);
+ Ui::FontsPage *m_ui;
+};
+
+#endif // FONTSPAGE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.ui
new file mode 100644
index 00000000..b03b5fc0
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/fontspage.ui
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FontsPage</class>
+ <widget class="QWidget" name="FontsPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>517</width>
+ <height>320</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <item row="1" column="2">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>342</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0" colspan="3">
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="1">
+ <widget class="QLabel" name="generalFontLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>General:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2">
+ <widget class="QToolButton" name="changeGeneralFontButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="fixedFontLabel">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QToolButton" name="changeFixedWidthFontButton">
+ <property name="text">
+ <string>...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Fixed width:</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="2" column="0" colspan="3">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Expanding</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>280</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <widget class="QPushButton" name="createFontsConfButton">
+ <property name="text">
+ <string>Create fonts.conf</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="removeFontsConfButton">
+ <property name="text">
+ <string>Remove fonts.conf</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.cpp
new file mode 100644
index 00000000..ca9a3388
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QSettings>
+#include <QFileInfo>
+#include <QFileInfoList>
+#include <QDir>
+#include <QTreeWidgetItem>
+#include <QImageReader>
+#include <QLocale>
+#include "lthemeengine.h"
+#include "iconthemepage.h"
+#include "ui_iconthemepage.h"
+
+IconThemePage::IconThemePage(QWidget *parent) :
+ TabPage(parent),
+ m_ui(new Ui::IconThemePage)
+{
+ m_ui->setupUi(this);
+ loadThemes();
+ readSettings();
+}
+
+IconThemePage::~IconThemePage()
+{
+ delete m_ui;
+}
+
+void IconThemePage::writeSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ QTreeWidgetItem *item = m_ui->treeWidget->currentItem();
+ if(item)
+ settings.setValue("Appearance/icon_theme", item->data(3, Qt::UserRole));
+}
+
+void IconThemePage::readSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ QString name = settings.value("Appearance/icon_theme").toString();
+
+ if(name.isEmpty())
+ return;
+
+ for(int i = 0; i < m_ui->treeWidget->topLevelItemCount(); ++i)
+ {
+ QTreeWidgetItem *item = m_ui->treeWidget->topLevelItem(i);
+ if(item->data(3, Qt::UserRole).toString() == name)
+ {
+ m_ui->treeWidget->setCurrentItem(item);
+ break;
+ }
+ }
+}
+
+void IconThemePage::loadThemes()
+{
+ QFileInfoList themeFileList;
+ foreach(QString path, lthemeengine::iconPaths())
+ {
+ QDir dir(path);
+ dir.setFilter(QDir::Dirs | QDir::NoDotDot | QDir::NoDot);
+ foreach (QFileInfo info, dir.entryInfoList())
+ {
+ QDir themeDir(info.absoluteFilePath());
+ themeDir.setFilter(QDir::Files);
+ themeFileList << themeDir.entryInfoList(QStringList() << "index.theme");
+ }
+ }
+
+ foreach(QFileInfo info, themeFileList)
+ {
+ loadTheme(info.canonicalFilePath());
+ }
+}
+
+void IconThemePage::loadTheme(const QString &path)
+{
+ QSettings config(path, QSettings::IniFormat);
+ config.setIniCodec("UTF-8");
+
+ config.beginGroup("Icon Theme");
+ QStringList dirs = config.value("Directories").toStringList();
+ if(dirs.isEmpty() || config.value("Hidden", false).toBool())
+ return;
+
+ QString name, comment;
+ QString lang = QLocale::system().name();
+
+ name = config.value(QString("Name[%1]").arg(lang)).toString();
+ comment = config.value(QString("Comment[%1]").arg(lang)).toString();
+
+ if(lang.contains("_"))
+ lang = lang.split("_").first();
+
+ if(name.isEmpty())
+ name = config.value(QString("Name[%1]").arg(lang)).toString();
+
+ if(comment.isEmpty())
+ comment = config.value(QString("Comment[%1]").arg(lang)).toString();
+
+ if(name.isEmpty())
+ name = config.value("Name").toString();
+
+ if(comment.isEmpty())
+ comment = config.value("Comment").toString();
+
+ config.endGroup();
+
+ QIcon icon1 = findIcon(path, 24, "document-save");
+ QIcon icon2 = findIcon(path, 24, "document-print");
+ QIcon icon3 = findIcon(path, 24, "media-playback-stop");
+
+ QTreeWidgetItem *item = new QTreeWidgetItem();
+ item->setIcon(0, icon1);
+ item->setIcon(1, icon2);
+ item->setIcon(2, icon3);
+ item->setText(3, name);
+ item->setData(3, Qt::UserRole, QFileInfo(path).path().section("/", -1));
+ item->setToolTip(3, comment);
+ item->setSizeHint(0, QSize(24,24));
+ m_ui->treeWidget->addTopLevelItem(item);
+
+ m_ui->treeWidget->resizeColumnToContents(0);
+ m_ui->treeWidget->resizeColumnToContents(1);
+ m_ui->treeWidget->resizeColumnToContents(2);
+ m_ui->treeWidget->resizeColumnToContents(3);
+}
+
+QIcon IconThemePage::findIcon(const QString &themePath, int size, const QString &name)
+{
+ QSettings config(themePath, QSettings::IniFormat);
+ config.beginGroup("Icon Theme");
+ QStringList dirs = config.value("Directories").toStringList();
+ QStringList parents = config.value("Inherits").toStringList();
+ bool haveInherits = config.contains("Inherits");
+ config.endGroup();
+
+ foreach (QString dir, dirs)
+ {
+ config.beginGroup(dir);
+ if(config.value("Size").toInt() == size)
+ {
+ QDir iconDir = QFileInfo(themePath).path() + "/" + dir;
+ iconDir.setFilter(QDir::Files);
+ iconDir.setNameFilters(QStringList () << name + ".*");
+ if(iconDir.entryInfoList().isEmpty())
+ continue;
+ return QIcon(iconDir.entryInfoList().first().absoluteFilePath());
+ }
+ config.endGroup();
+ }
+
+ foreach (QString dir, dirs)
+ {
+ config.beginGroup(dir);
+ if(abs(config.value("Size").toInt() - size) < 4)
+ {
+ QDir iconDir = QFileInfo(themePath).path() + "/" + dir;
+ iconDir.setFilter(QDir::Files);
+ iconDir.setNameFilters(QStringList () << name + ".*");
+ if(iconDir.entryInfoList().isEmpty())
+ continue;
+ return QIcon(iconDir.entryInfoList().first().absoluteFilePath());
+ }
+ config.endGroup();
+ }
+
+ if (!haveInherits)
+ return QIcon();
+
+ parents.append("hicolor"); //add fallback themes
+ parents.append("gnome");
+ parents.removeDuplicates();
+
+ foreach (QString parent, parents)
+ {
+ QString parentThemePath = QDir(QFileInfo(themePath).path() + "/../" + parent).canonicalPath() + "/index.theme";
+
+ if(!QFile::exists(parentThemePath) || parentThemePath == themePath)
+ continue;
+
+ QIcon icon = findIcon(parentThemePath, size, name);
+ if(!icon.isNull())
+ return icon;
+ }
+
+ return QIcon();
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.h
new file mode 100644
index 00000000..0ccd64e0
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ICONTHEMEPAGE_H
+#define ICONTHEMEPAGE_H
+
+#include <QIcon>
+#include "tabpage.h"
+
+namespace Ui {
+class IconThemePage;
+}
+
+class IconThemePage : public TabPage
+{
+ Q_OBJECT
+
+public:
+ explicit IconThemePage(QWidget *parent = 0);
+ ~IconThemePage();
+
+ void writeSettings();
+
+private:
+ void readSettings();
+ void loadThemes();
+ void loadTheme(const QString &path);
+ QIcon findIcon(const QString &themePath, int size, const QString &name);
+ Ui::IconThemePage *m_ui;
+};
+
+#endif // ICONTHEMEPAGE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.ui
new file mode 100644
index 00000000..a6385041
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/iconthemepage.ui
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>IconThemePage</class>
+ <widget class="QWidget" name="IconThemePage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>400</width>
+ <height>300</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Form</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTreeWidget" name="treeWidget">
+ <property name="columnCount">
+ <number>4</number>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">2</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">3</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">4</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.cpp
new file mode 100644
index 00000000..a9f40080
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.cpp
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QSettings>
+#include <QApplication>
+#include <QDialogButtonBox>
+#include "lthemeengine.h"
+#include "interfacepage.h"
+#include "ui_interfacepage.h"
+
+InterfacePage::InterfacePage(QWidget *parent) :
+ TabPage(parent),
+ m_ui(new Ui::InterfacePage)
+{
+ m_ui->setupUi(this);
+
+ m_ui->buttonLayoutComboBox->addItem("Windows", QDialogButtonBox::WinLayout);
+ m_ui->buttonLayoutComboBox->addItem("Mac OS X", QDialogButtonBox::MacLayout);
+ m_ui->buttonLayoutComboBox->addItem("KDE", QDialogButtonBox::KdeLayout);
+ m_ui->buttonLayoutComboBox->addItem("GNOME", QDialogButtonBox::GnomeLayout);
+
+ m_ui->toolButtonStyleComboBox->addItem(tr("Only display the icon"), Qt::ToolButtonIconOnly);
+ m_ui->toolButtonStyleComboBox->addItem(tr("Only display the text"), Qt::ToolButtonTextOnly);
+ m_ui->toolButtonStyleComboBox->addItem(tr("The text appears beside the icon"), Qt::ToolButtonTextBesideIcon);
+ m_ui->toolButtonStyleComboBox->addItem(tr("The text appears under the icon"), Qt::ToolButtonTextUnderIcon);
+ m_ui->toolButtonStyleComboBox->addItem(tr("Follow the application style"), Qt::ToolButtonFollowStyle);
+
+ readSettings();
+}
+
+InterfacePage::~InterfacePage()
+{
+ delete m_ui;
+}
+
+void InterfacePage::writeSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Interface");
+ settings.setValue("double_click_interval", m_ui->doubleClickIntervalSpinBox->value());
+ settings.setValue("cursor_flash_time", m_ui->cursorFlashTimeSpinBox->value());
+ settings.setValue("buttonbox_layout", m_ui->buttonLayoutComboBox->currentData());
+ settings.setValue("menus_have_icons", m_ui->menuIconsCheckBox->isChecked());
+ settings.setValue("activate_item_on_single_click", m_ui->singleClickCheckBox->checkState());
+ settings.setValue("dialog_buttons_have_icons", m_ui->dialogIconsCheckBox->checkState());
+ settings.setValue("toolbutton_style", m_ui->toolButtonStyleComboBox->currentData());
+ settings.setValue("wheel_scroll_lines", m_ui->wheelScrollLinesSpinBox->value());
+
+ QStringList effects;
+ if(m_ui->guiEffectsCheckBox->isChecked())
+ effects << "General";
+
+ if(m_ui->menuEffectComboBox->currentIndex() == 1)
+ effects << "AnimateMenu";
+ else if(m_ui->menuEffectComboBox->currentIndex() == 2)
+ effects << "FadeMenu";
+
+ if(m_ui->comboBoxEffectComboBox->currentIndex() == 1)
+ effects << "AnimateCombo";
+
+ if(m_ui->toolTipEffectComboBox->currentIndex() == 1)
+ effects << "AnimateTooltip";
+ else if(m_ui->toolTipEffectComboBox->currentIndex() == 2)
+ effects << "FadeTooltip";
+
+ if(m_ui->toolBoxEffectComboBox->currentIndex() == 1)
+ effects << "AnimateToolBox";
+
+ settings.setValue("gui_effects", effects);
+ settings.endGroup();
+}
+
+void InterfacePage::readSettings()
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.beginGroup("Interface");
+ m_ui->doubleClickIntervalSpinBox->setValue(qApp->doubleClickInterval());
+ m_ui->cursorFlashTimeSpinBox->setValue(qApp->cursorFlashTime());
+
+ m_ui->guiEffectsCheckBox->setChecked(qApp->isEffectEnabled(Qt::UI_General));
+
+ int layout = settings.value("buttonbox_layout", style()->styleHint(QStyle::SH_DialogButtonLayout)).toInt();
+ int index = m_ui->buttonLayoutComboBox->findData(layout);
+ if(index >= 0)
+ m_ui->buttonLayoutComboBox->setCurrentIndex(index);
+
+ if(qApp->isEffectEnabled(Qt::UI_AnimateMenu))
+ m_ui->menuEffectComboBox->setCurrentIndex(1);
+ else if(qApp->isEffectEnabled(Qt::UI_FadeMenu))
+ m_ui->menuEffectComboBox->setCurrentIndex(2);
+
+ if(qApp->isEffectEnabled(Qt::UI_AnimateCombo))
+ m_ui->comboBoxEffectComboBox->setCurrentIndex(1);
+
+ if(qApp->isEffectEnabled(Qt::UI_AnimateTooltip))
+ m_ui->toolTipEffectComboBox->setCurrentIndex(1);
+ else if(qApp->isEffectEnabled(Qt::UI_FadeTooltip))
+ m_ui->toolTipEffectComboBox->setCurrentIndex(2);
+
+ if(qApp->isEffectEnabled(Qt::UI_AnimateToolBox))
+ m_ui->toolBoxEffectComboBox->setCurrentIndex(1);
+
+ m_ui->singleClickCheckBox->setCheckState((Qt::CheckState)settings.value("activate_item_on_single_click", Qt::PartiallyChecked).toInt());
+ m_ui->dialogIconsCheckBox->setCheckState((Qt::CheckState)settings.value("dialog_buttons_have_icons", Qt::PartiallyChecked).toInt());
+ m_ui->menuIconsCheckBox->setChecked(!qApp->testAttribute(Qt::AA_DontShowIconsInMenus));
+
+ int toolbarStyle = settings.value("toolbutton_style", Qt::ToolButtonFollowStyle).toInt();
+ index = m_ui->toolButtonStyleComboBox->findData(toolbarStyle);
+ if(index >= 0)
+ m_ui->toolButtonStyleComboBox->setCurrentIndex(index);
+
+ m_ui->wheelScrollLinesSpinBox->setValue(settings.value("wheel_scroll_lines", 3).toInt());
+
+ settings.endGroup();
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.h
new file mode 100644
index 00000000..637b6bf1
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef INTERFACEPAGE_H
+#define INTERFACEPAGE_H
+
+#include "tabpage.h"
+
+namespace Ui {
+class InterfacePage;
+}
+
+class InterfacePage : public TabPage
+{
+ Q_OBJECT
+
+public:
+ explicit InterfacePage(QWidget *parent = 0);
+ ~InterfacePage();
+
+ void writeSettings();
+
+private:
+ void readSettings();
+
+ Ui::InterfacePage *m_ui;
+};
+
+#endif // INTERFACEPAGE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.ui
new file mode 100644
index 00000000..ca9d0291
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/interfacepage.ui
@@ -0,0 +1,327 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InterfacePage</class>
+ <widget class="QWidget" name="InterfacePage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>498</width>
+ <height>449</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="0">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>259</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0">
+ <layout class="QFormLayout" name="formLayout">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Double click interval:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>Cursor flash time:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>ComboBox effect:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>ToolTip effect:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>ToolBox effect:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="QSpinBox" name="doubleClickIntervalSpinBox">
+ <property name="suffix">
+ <string> ms</string>
+ </property>
+ <property name="maximum">
+ <number>2000</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QSpinBox" name="cursorFlashTimeSpinBox">
+ <property name="suffix">
+ <string> ms</string>
+ </property>
+ <property name="maximum">
+ <number>4000</number>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1">
+ <widget class="QComboBox" name="comboBoxEffectComboBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Disable</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Animate</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="6" column="1">
+ <widget class="QComboBox" name="toolTipEffectComboBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Disable</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Animate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Fade</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="7" column="1">
+ <widget class="QComboBox" name="toolBoxEffectComboBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Disable</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Animate</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Menu effect:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="QComboBox" name="menuEffectComboBox">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <item>
+ <property name="text">
+ <string>Disable</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Animate</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Fade</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QCheckBox" name="guiEffectsCheckBox">
+ <property name="text">
+ <string>Enable gui effects</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0">
+ <widget class="QLabel" name="label_7">
+ <property name="text">
+ <string>Dialog buttons layout:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="1">
+ <widget class="QComboBox" name="buttonLayoutComboBox"/>
+ </item>
+ <item row="10" column="0" colspan="2">
+ <widget class="QCheckBox" name="menuIconsCheckBox">
+ <property name="text">
+ <string>Menus have icons</string>
+ </property>
+ </widget>
+ </item>
+ <item row="9" column="0" colspan="2">
+ <widget class="QCheckBox" name="dialogIconsCheckBox">
+ <property name="text">
+ <string>Dialog buttons have icons</string>
+ </property>
+ <property name="tristate">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QCheckBox" name="singleClickCheckBox">
+ <property name="text">
+ <string>Activate item on single-click</string>
+ </property>
+ <property name="tristate">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="11" column="0">
+ <widget class="QLabel" name="label_8">
+ <property name="text">
+ <string>Toolbar button style:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="11" column="1">
+ <widget class="QComboBox" name="toolButtonStyleComboBox"/>
+ </item>
+ <item row="12" column="0">
+ <widget class="QLabel" name="label_9">
+ <property name="text">
+ <string>Mouse wheel scroll lines:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="12" column="1">
+ <widget class="QSpinBox" name="wheelScrollLinesSpinBox">
+ <property name="minimum">
+ <number>1</number>
+ </property>
+ <property name="maximum">
+ <number>20</number>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="0" column="1">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>238</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>guiEffectsCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>menuEffectComboBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>126</x>
+ <y>86</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>201</x>
+ <y>114</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>guiEffectsCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>comboBoxEffectComboBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>75</x>
+ <y>84</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>160</x>
+ <y>153</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>guiEffectsCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>toolTipEffectComboBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>54</x>
+ <y>84</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>155</x>
+ <y>184</y>
+ </hint>
+ </hints>
+ </connection>
+ <connection>
+ <sender>guiEffectsCheckBox</sender>
+ <signal>toggled(bool)</signal>
+ <receiver>toolBoxEffectComboBox</receiver>
+ <slot>setEnabled(bool)</slot>
+ <hints>
+ <hint type="sourcelabel">
+ <x>36</x>
+ <y>91</y>
+ </hint>
+ <hint type="destinationlabel">
+ <x>156</x>
+ <y>216</y>
+ </hint>
+ </hints>
+ </connection>
+ </connections>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp
new file mode 100644
index 00000000..65328963
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QDir>
+#include <QLocale>
+#include "lthemeengine.h"
+
+#ifndef LTHEMEENGINE_DATADIR
+#define LTHEMEENGINE_DATADIR "/usr/local/share"
+#endif
+
+
+QString lthemeengine::configPath()
+{
+ return QDir::homePath() + "/.config/lthemeengine/";
+}
+
+QString lthemeengine::configFile()
+{
+ return configPath() + "lthemeengine.conf";
+}
+
+QStringList lthemeengine::iconPaths()
+{
+ QString xdgDataDirs = qgetenv("XDG_DATA_DIRS");
+ QString xdgDataHome = qgetenv("XDG_DATA_HOME");
+
+ QStringList paths;
+ paths << QDir::homePath() + "/.icons/";
+
+ if(xdgDataDirs.isEmpty())
+ {
+ paths << "/usr/share/icons";
+ paths << "/usr/local/share/icons";
+ }
+ else
+ {
+ foreach (QString p, xdgDataDirs.split(":"))
+ paths << QDir(p + "/icons/").absolutePath();
+ }
+
+ if(xdgDataHome.isEmpty())
+ xdgDataHome = QDir::homePath() + "/.local/share";
+
+ paths << "/usr/share/pixmaps";
+ paths << xdgDataHome + "/icons";
+ paths.removeDuplicates();
+
+ //remove invalid
+ foreach (QString p, paths)
+ {
+ if(!QDir(p).exists())
+ paths.removeAll(p);
+ }
+ return paths;
+}
+
+QString lthemeengine::userStyleSheetPath()
+{
+ return configPath() + "qss/";
+}
+
+QStringList lthemeengine::sharedStyleSheetPath()
+ {
+ QStringList dirs;
+ dirs << QString(getenv("XDG_CONFIG_HOME"));
+ dirs << QString(getenv("XDG_CONFIG_DIRS")).split(":");
+ for(int i=0; i<dirs.length(); i++){
+ dirs[i].append("/lthemeengine/colors/");
+ }
+ if(dirs.isEmpty()){
+ dirs << LTHEMEENGINE_DATADIR"/lthemeengine/qss/"; //no XDG settings - use the hardcoded path
+ }
+ return dirs;
+ }
+
+ QString lthemeengine::userColorSchemePath(){
+ return configPath() + "colors/";
+ }
+
+QStringList lthemeengine::sharedColorSchemePath()
+ {
+ QStringList dirs;
+ dirs << QString(getenv("XDG_CONFIG_HOME"));
+ dirs << QString(getenv("XDG_CONFIG_DIRS")).split(":");
+ for(int i=0; i<dirs.length(); i++){
+ dirs[i].append("/lthemeengine/colors/");
+ }
+ if(dirs.isEmpty()){
+ dirs << LTHEMEENGINE_DATADIR"/lthemeengine/colors/"; //no XDG settings - use the hardcoded path
+ }
+ return dirs;
+ }
+
+QString lthemeengine::systemLanguageID()
+{
+#ifdef Q_OS_UNIX
+ QByteArray v = qgetenv ("LC_ALL");
+ if (v.isEmpty())
+ v = qgetenv ("LC_MESSAGES");
+ if (v.isEmpty())
+ v = qgetenv ("LANG");
+ if (!v.isEmpty())
+ return QLocale (v).name();
+#endif
+ return QLocale::system().name();
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.desktop b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.desktop
new file mode 100644
index 00000000..7eb91bee
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.desktop
@@ -0,0 +1,9 @@
+[Desktop Entry]
+X-Desktop-File-Install-Version=0.11
+Name=Lumine Theme Engine
+Comment=Lumina Theme Engine
+Exec=lthemeengine
+Icon=preferences-desktop-theme
+Terminal=false
+Type=Application
+Categories=Settings;DesktopSettings;Qt;
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.h
new file mode 100644
index 00000000..171f720a
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LTHEMEENGINE_H
+#define LTHEMEENGINE_H
+
+#define LTHEMEENGINE_VERSION_MAJOR 0
+#define LTHEMEENGINE_VERSION_MINOR 33
+
+#define LTHEMEENGINE_TOSTRING(s) #s
+#define LTHEMEENGINE_STRINGIFY(s) LTHEMEENGINE_TOSTRING(s)
+
+#define LTHEMEENGINE_VERSION_INT (LTHEMEENGINE_VERSION_MAJOR<<8 | LTHEMEENGINE_VERSION_MINOR)
+#define LTHEMEENGINE_VERSION_STR LTHEMEENGINE_STRINGIFY(LTHEMEENGINE_VERSION_MAJOR.QT5CT_VERSION_MINOR)
+
+#include <QString>
+#include <QStringList>
+
+class lthemeengine
+{
+public:
+ static QString configPath();
+ static QString configFile();
+ static QStringList iconPaths();
+ static QString userStyleSheetPath();
+ static QStringList sharedStyleSheetPath();
+ static QString userColorSchemePath();
+ static QStringList sharedColorSchemePath();
+ static QString systemLanguageID();
+
+private:
+ lthemeengine() {}
+};
+
+#endif // LTHEMEENGINE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.pro b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.pro
new file mode 100644
index 00000000..cc36ee5b
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/lthemeengine.pro
@@ -0,0 +1,55 @@
+include(../../lthemeengine.pri)
+
+TEMPLATE = app
+
+QT += widgets
+
+SOURCES += \
+ main.cpp \
+ mainwindow.cpp \
+ tabpage.cpp \
+ appearancepage.cpp \
+ fontspage.cpp \
+ lthemeengine.cpp \
+ paletteeditdialog.cpp \
+ iconthemepage.cpp \
+ interfacepage.cpp \
+ fontconfigdialog.cpp \
+ qsspage.cpp \
+ qsseditordialog.cpp
+
+FORMS += \
+ mainwindow.ui \
+ appearancepage.ui \
+ fontspage.ui \
+ paletteeditdialog.ui \
+ iconthemepage.ui \
+ interfacepage.ui \
+ fontconfigdialog.ui \
+ previewform.ui \
+ qsspage.ui \
+ qsseditordialog.ui
+
+HEADERS += \
+ mainwindow.h \
+ tabpage.h \
+ appearancepage.h \
+ fontspage.h \
+ lthemeengine.h \
+ paletteeditdialog.h \
+ iconthemepage.h \
+ interfacepage.h \
+ fontconfigdialog.h \
+ qsspage.h \
+ qsseditordialog.h
+
+!equals (DISABLE_WIDGETS,1) {
+ DEFINES += USE_WIDGETS
+}
+
+target.path = $$BINDIR
+
+desktop.files = lthemeengine.desktop
+desktop.path = $$DATADIR/applications
+
+INSTALLS += target desktop
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/main.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/main.cpp
new file mode 100644
index 00000000..1961d17d
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/main.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QApplication>
+#include <QLibraryInfo>
+#include <QLocale>
+#include "lthemeengine.h"
+#include <QTranslator>
+#include <QMessageBox>
+#include <QProcessEnvironment>
+#include <QStyleFactory>
+#include "mainwindow.h"
+
+int main(int argc, char **argv)
+{
+ QApplication app(argc, argv);
+ QTranslator translator;
+ QString locale = lthemeengine::systemLanguageID();
+ translator.load(QString(":/lthemeengine_") + locale);
+ app.installTranslator(&translator);
+
+ QTranslator qt_translator;
+ qt_translator.load(QLibraryInfo::location (QLibraryInfo::TranslationsPath) + "/qtbase_" + locale);
+ app.installTranslator(&qt_translator);
+
+ qDebug("Configuration path: %s", qPrintable(lthemeengine::configPath()));
+ qDebug("Shared QSS path: %s", qPrintable(lthemeengine::sharedStyleSheetPath().join(", ")));
+
+ //checking environment
+ QStringList errorMessages;
+ QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+
+ if(env.contains("QT_STYLE_OVERRIDE"))
+ {
+ errorMessages << app.translate("main", "Please remove the <b>QT_STYLE_OVERRIDE</b> environment variable");
+ }
+
+ if(env.value("QT_QPA_PLATFORMTHEME") != "lthemeengine")
+ {
+ errorMessages << app.translate("main", "The <b>QT_QPA_PLATFORMTHEME</b> environment "
+ "variable is not set correctly");
+ }
+
+ if(!QStyleFactory::keys().contains("lthemeengine-style"))
+ {
+ errorMessages << app.translate("main", "Unable to find <b>liblthemeengine-style.so</b>");
+ }
+
+ if(!errorMessages.isEmpty())
+ {
+ QMessageBox::critical(0, app.translate("main", "Error"), errorMessages.join("<br><br>"));
+ return 0;
+ }
+
+ MainWindow w;
+ w.show();
+
+ return app.exec();
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.cpp
new file mode 100644
index 00000000..ed658e2e
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QApplication>
+#include <QSettings>
+#include "lthemeengine.h"
+#include "mainwindow.h"
+#include "appearancepage.h"
+#include "fontspage.h"
+#include "iconthemepage.h"
+#include "interfacepage.h"
+#include "qsspage.h"
+#include "ui_mainwindow.h"
+
+MainWindow::MainWindow(QWidget *parent) :
+ QWidget(parent),
+ m_ui(new Ui::MainWindow)
+{
+ m_ui->setupUi(this);
+ m_ui->tabWidget->addTab(new AppearancePage(this), tr("Appearance"));
+ m_ui->tabWidget->addTab(new FontsPage(this), tr("Fonts"));
+ m_ui->tabWidget->addTab(new IconThemePage(this), tr("Icon Theme"));
+ m_ui->tabWidget->addTab(new InterfacePage(this), tr("Interface"));
+#ifdef USE_WIDGETS
+ m_ui->tabWidget->addTab(new QSSPage(this), tr("Style Sheets"));
+#endif
+
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ restoreGeometry(settings.value("SettingsWindow/geometry").toByteArray());
+
+ setWindowIcon(QIcon::fromTheme("preferences-desktop-theme"));
+
+ m_ui->versionLabel->setText(tr("Version: %1").arg(LTHEMEENGINE_VERSION_STR));
+}
+
+MainWindow::~MainWindow()
+{
+ delete m_ui;
+}
+
+void MainWindow::closeEvent(QCloseEvent *)
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.setValue("SettingsWindow/geometry", saveGeometry());
+}
+
+void MainWindow::on_buttonBox_clicked(QAbstractButton *button)
+{
+ int id = m_ui->buttonBox->standardButton(button);
+ if(id == QDialogButtonBox::Ok || id == QDialogButtonBox::Apply)
+ {
+ for(int i = 0; i < m_ui->tabWidget->count(); ++i)
+ {
+ TabPage *p = qobject_cast<TabPage*>(m_ui->tabWidget->widget(i));
+ if(p)
+ p->writeSettings();
+ }
+ }
+
+ if(id == QDialogButtonBox::Ok || id == QDialogButtonBox::Cancel)
+ {
+ close();
+ qApp->quit();
+ }
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.h
new file mode 100644
index 00000000..f532141c
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include <QWidget>
+
+class QAbstractButton;
+
+namespace Ui {
+class MainWindow;
+}
+
+class MainWindow : public QWidget
+{
+ Q_OBJECT
+
+public:
+ explicit MainWindow(QWidget *parent = 0);
+ ~MainWindow();
+
+private slots:
+ void on_buttonBox_clicked(QAbstractButton *button);
+
+private:
+ void closeEvent(QCloseEvent *);
+
+ Ui::MainWindow *m_ui;
+};
+
+#endif // MAINWINDOW_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.ui
new file mode 100644
index 00000000..5bdab6d7
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/mainwindow.ui
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>MainWindow</class>
+ <widget class="QWidget" name="MainWindow">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>438</width>
+ <height>374</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Qt5 Configuration Tool</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item row="0" column="0" colspan="2">
+ <widget class="QTabWidget" name="tabWidget"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="versionLabel">
+ <property name="text">
+ <string notr="true">...</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.cpp
new file mode 100644
index 00000000..0f8fcf66
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.cpp
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QPalette>
+#include <QColorDialog>
+#include <QSettings>
+#include "lthemeengine.h"
+#include "paletteeditdialog.h"
+#include "ui_paletteeditdialog.h"
+
+PaletteEditDialog::PaletteEditDialog(const QPalette &palette, QStyle *currentStyle, QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::PaletteEditDialog)
+{
+ m_currentStyle = currentStyle;
+ m_ui->setupUi(this);
+ m_ui->tableWidget->setColumnCount(3);
+ m_ui->tableWidget->setRowCount(QPalette::NColorRoles);
+ m_ui->tableWidget->verticalHeader()->setDefaultSectionSize(fontMetrics().lineSpacing() + 10);
+ m_ui->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
+ m_ui->tableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
+
+ QStringList labels;
+ labels << tr("Active") << tr("Inactive") << tr("Disabled");
+ m_ui->tableWidget->setHorizontalHeaderLabels(labels);
+ setPalette(palette);
+
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ restoreGeometry(settings.value("PaletteEditor/geometry").toByteArray());
+}
+
+PaletteEditDialog::~PaletteEditDialog()
+{
+ delete m_ui;
+}
+
+QPalette PaletteEditDialog::selectedPalette() const
+{
+ QPalette palette;
+ for(int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ palette.setBrush(QPalette::Active, QPalette::ColorRole(i), m_ui->tableWidget->item(i,0)->backgroundColor());
+ palette.setBrush(QPalette::Inactive, QPalette::ColorRole(i), m_ui->tableWidget->item(i,1)->backgroundColor());
+ palette.setBrush(QPalette::Disabled, QPalette::ColorRole(i), m_ui->tableWidget->item(i,2)->backgroundColor());
+ }
+ return palette;
+}
+
+void PaletteEditDialog::setPalette(const QPalette &palette)
+{
+ for(int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ if(!m_ui->tableWidget->item(i,0))
+ m_ui->tableWidget->setItem(i, 0, new QTableWidgetItem());
+ if(!m_ui->tableWidget->item(i,1))
+ m_ui->tableWidget->setItem(i, 1, new QTableWidgetItem());
+ if(!m_ui->tableWidget->item(i,2))
+ m_ui->tableWidget->setItem(i, 2, new QTableWidgetItem());
+
+ m_ui->tableWidget->item(i,0)->setBackgroundColor(palette.color(QPalette::Active, QPalette::ColorRole(i)));
+ m_ui->tableWidget->item(i,1)->setBackgroundColor(palette.color(QPalette::Inactive, QPalette::ColorRole(i)));
+ m_ui->tableWidget->item(i,2)->setBackgroundColor(palette.color(QPalette::Disabled, QPalette::ColorRole(i)));
+ }
+
+ QStringList labels;
+ labels << tr("Window text") << tr("Button background") << tr("Bright") << tr("Less bright") << tr("Dark") << tr("Less dark")
+ << tr("Normal text") << tr("Bright text") << tr("Button text") << tr("Normal background") << tr("Window") << tr("Shadow")
+ << tr("Highlight") << tr("Highlighted text") << tr("Link") << tr("Visited link")
+ << tr("Alternate background") << tr("Default") << tr("Tooltip background") << tr("Tooltip text");
+ m_ui->tableWidget->setVerticalHeaderLabels(labels);
+}
+
+void PaletteEditDialog::hideEvent(QHideEvent *)
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.setValue("PaletteEditor/geometry", saveGeometry());
+}
+
+void PaletteEditDialog::on_tableWidget_itemClicked(QTableWidgetItem *item)
+{
+ QColor color = QColorDialog::getColor(item->backgroundColor(), this, tr("Select Color"));
+ if(color.isValid())
+ {
+ item->setBackgroundColor(color);
+ emit paletteChanged(selectedPalette());
+ }
+}
+
+void PaletteEditDialog::on_resetPaletteButton_clicked()
+{
+ setPalette(m_currentStyle->standardPalette());
+ emit paletteChanged(selectedPalette());
+}
+
+void PaletteEditDialog::on_buildInactiveButton_clicked()
+{
+ QPalette palette = selectedPalette();
+ for(int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ palette.setColor(QPalette::Inactive, QPalette::ColorRole(i),
+ palette.color(QPalette::Active, QPalette::ColorRole(i)));
+ }
+ setPalette(palette);
+ emit paletteChanged(selectedPalette());
+}
+
+void PaletteEditDialog::on_buildDisabledButton_clicked()
+{
+ QPalette palette = selectedPalette();
+ for(int i = 0; i < QPalette::NColorRoles; i++)
+ {
+ palette.setColor(QPalette::Disabled, QPalette::ColorRole(i),
+ palette.color(QPalette::Active, QPalette::ColorRole(i)));
+ }
+ palette.setColor(QPalette::Disabled, QPalette::ButtonText, Qt::darkGray);
+ palette.setColor(QPalette::Disabled, QPalette::WindowText, Qt::darkGray);
+ palette.setColor(QPalette::Disabled, QPalette::Text, Qt::darkGray);
+ palette.setColor(QPalette::Disabled, QPalette::HighlightedText, Qt::darkGray);
+ setPalette(palette);
+ emit paletteChanged(selectedPalette());
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.h
new file mode 100644
index 00000000..c8691a3c
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PALETTEEDITDIALOG_H
+#define PALETTEEDITDIALOG_H
+
+#include <QDialog>
+#include <QPalette>
+
+class QTableWidgetItem;
+class QStyle;
+
+namespace Ui {
+class PaletteEditDialog;
+}
+
+class PaletteEditDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit PaletteEditDialog(const QPalette &palette, QStyle *currentStyle, QWidget *parent = 0);
+ ~PaletteEditDialog();
+
+ QPalette selectedPalette() const;
+
+signals:
+ void paletteChanged(const QPalette &p);
+
+private slots:
+ void on_tableWidget_itemClicked(QTableWidgetItem *item);
+ void on_resetPaletteButton_clicked();
+ void on_buildInactiveButton_clicked();
+ void on_buildDisabledButton_clicked();
+
+private:
+ void setPalette(const QPalette &palette);
+ void hideEvent(QHideEvent *);
+ Ui::PaletteEditDialog *m_ui;
+ QStyle *m_currentStyle;
+};
+
+#endif // PALETTEEDITDIALOG_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.ui
new file mode 100644
index 00000000..6ca6350f
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/paletteeditdialog.ui
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PaletteEditDialog</class>
+ <widget class="QDialog" name="PaletteEditDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>631</width>
+ <height>529</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Palette Editor</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item row="3" column="0">
+ <widget class="QPushButton" name="buildInactiveButton">
+ <property name="text">
+ <string>Build inactive palette</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1">
+ <widget class="QPushButton" name="buildDisabledButton">
+ <property name="text">
+ <string>Build disabled palette</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>117</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="9" column="0" colspan="5">
+ <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>
+ <item row="0" column="0" colspan="5">
+ <widget class="QTableWidget" name="tableWidget">
+ <property name="editTriggers">
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ <property name="columnCount">
+ <number>0</number>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2">
+ <widget class="QPushButton" name="resetPaletteButton">
+ <property name="text">
+ <string>Reset palette</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>PaletteEditDialog</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>PaletteEditDialog</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>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/previewform.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/previewform.ui
new file mode 100644
index 00000000..508201db
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/previewform.ui
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>PreviewForm</class>
+ <widget class="QWidget" name="PreviewForm">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>281</width>
+ <height>130</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Preview Window</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="tab_3">
+ <attribute name="title">
+ <string>Tab 1</string>
+ </attribute>
+ <layout class="QGridLayout" name="gridLayout_4">
+ <item row="1" column="0">
+ <widget class="QPushButton" name="pushButton_3">
+ <property name="text">
+ <string>PushButton</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QProgressBar" name="progressBar_2">
+ <property name="value">
+ <number>24</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0">
+ <widget class="QLineEdit" name="lineEdit_2"/>
+ </item>
+ <item row="0" column="1" colspan="2">
+ <widget class="QSpinBox" name="spinBox_2"/>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="tab_4">
+ <attribute name="title">
+ <string>Tab 2</string>
+ </attribute>
+ <layout class="QVBoxLayout" name="verticalLayout_3">
+ <item>
+ <widget class="QRadioButton" name="radioButton_7">
+ <property name="text">
+ <string>RadioButton</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="checkBox_2">
+ <property name="text">
+ <string>CheckBox</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.cpp
new file mode 100644
index 00000000..b92b5619
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QFile>
+#include <QSettings>
+#include "lthemeengine.h"
+#include "qsseditordialog.h"
+#include "ui_qsseditordialog.h"
+
+QSSEditorDialog::QSSEditorDialog(const QString &filePath, QWidget *parent) :
+ QDialog(parent),
+ m_ui(new Ui::QSSEditorDialog)
+{
+ m_ui->setupUi(this);
+ m_filePath = filePath;
+
+ QFile file(filePath);
+ file.open(QIODevice::ReadOnly);
+ m_ui->textEdit->setPlainText(QString::fromUtf8(file.readAll()));
+ setWindowTitle(tr("%1 - Style Sheet Editor").arg(file.fileName()));
+
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ restoreGeometry(settings.value("QSSEditor/geometry").toByteArray());
+}
+
+QSSEditorDialog::~QSSEditorDialog()
+{
+ delete m_ui;
+}
+
+void QSSEditorDialog::save()
+{
+ QFile file(m_filePath);
+ file.open(QIODevice::WriteOnly);
+ file.write(m_ui->textEdit->toPlainText().toUtf8());
+}
+
+void QSSEditorDialog::hideEvent(QHideEvent *)
+{
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ settings.setValue("QSSEditor/geometry", saveGeometry());
+}
+
+void QSSEditorDialog::on_buttonBox_clicked(QAbstractButton *button)
+{
+ QDialogButtonBox::StandardButton id = m_ui->buttonBox->standardButton(button);
+ if(id == QDialogButtonBox::Ok)
+ {
+ save();
+ accept();
+ }
+ else if(id == QDialogButtonBox::Save)
+ {
+ save();
+ }
+ else
+ {
+ reject();
+ }
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.h
new file mode 100644
index 00000000..e2a6c773
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef QSSEDITORDIALOG_H
+#define QSSEDITORDIALOG_H
+
+#include <QDialog>
+#include <QString>
+
+namespace Ui {
+class QSSEditorDialog;
+}
+
+class QAbstractButton;
+
+class QSSEditorDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit QSSEditorDialog(const QString &filePath, QWidget *parent = 0);
+ ~QSSEditorDialog();
+
+private slots:
+ void on_buttonBox_clicked(QAbstractButton *button);
+
+private:
+ void save();
+ void hideEvent(QHideEvent *);
+ Ui::QSSEditorDialog *m_ui;
+ QString m_filePath;
+};
+
+#endif // QSSEDITORDIALOG_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.ui
new file mode 100644
index 00000000..7627b4d4
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsseditordialog.ui
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QSSEditorDialog</class>
+ <widget class="QDialog" name="QSSEditorDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>643</width>
+ <height>499</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Style Sheet Editor</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
+ <number>6</number>
+ </property>
+ <item>
+ <widget class="QTextEdit" name="textEdit">
+ <property name="acceptRichText">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QDialogButtonBox" name="buttonBox">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="standardButtons">
+ <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Save</set>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp
new file mode 100644
index 00000000..10f21f48
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.cpp
@@ -0,0 +1,232 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <QSettings>
+#include <QDir>
+#include <QInputDialog>
+#include <QMessageBox>
+#include <QFile>
+#include <QMenu>
+#include "lthemeengine.h"
+#include "qsseditordialog.h"
+#include "qsspage.h"
+#include "ui_qsspage.h"
+
+#define QSS_FULL_PATH_ROLE (Qt::ItemDataRole(Qt::UserRole))
+#define QSS_WRITABLE_ROLE (Qt::ItemDataRole(Qt::UserRole + 1))
+
+QSSPage::QSSPage(QWidget *parent) :
+ TabPage(parent),
+ m_ui(new Ui::QSSPage)
+{
+ m_ui->setupUi(this);
+ QDir("/").mkpath(lthemeengine::userStyleSheetPath());
+
+ m_menu = new QMenu(this);
+ m_menu->addAction(QIcon::fromTheme("accessories-text-editor"), tr("Edit"), this, SLOT(on_editButton_clicked()));
+ m_menu->addAction(tr("Rename"), this, SLOT(on_renameButton_clicked()));
+ m_menu->addSeparator();
+ m_menu->addAction(QIcon::fromTheme("edit-delete"), tr("Remove"), this, SLOT(on_removeButton_clicked()));
+
+ readSettings();
+
+ //icons
+ m_ui->createButton->setIcon(QIcon::fromTheme("document-new"));
+ m_ui->editButton->setIcon(QIcon::fromTheme("accessories-text-editor"));
+ m_ui->removeButton->setIcon(QIcon::fromTheme("edit-delete"));
+}
+
+QSSPage::~QSSPage()
+{
+ delete m_ui;
+}
+
+void QSSPage::writeSettings()
+{
+ QStringList styleSheets;
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+
+ for(int i = 0; i < m_ui->qssListWidget->count(); ++i)
+ {
+ QListWidgetItem *item = m_ui->qssListWidget->item(i);
+ if(item->checkState() == Qt::Checked)
+ styleSheets << item->data(QSS_FULL_PATH_ROLE).toString();
+ }
+
+ settings.setValue("Interface/stylesheets", styleSheets);
+}
+
+void QSSPage::on_qssListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *)
+{
+ if(current)
+ {
+ m_ui->editButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
+ m_ui->removeButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
+ m_ui->renameButton->setEnabled(current->data(QSS_WRITABLE_ROLE).toBool());
+ }
+ else
+ {
+ m_ui->editButton->setEnabled(false);
+ m_ui->removeButton->setEnabled(false);
+ m_ui->renameButton->setEnabled(false);
+ }
+}
+
+void QSSPage::on_createButton_clicked()
+{
+ QString name = QInputDialog::getText(this, tr("Enter Style Sheet Name"), tr("File name:"));
+ if(name.isEmpty())
+ return;
+
+ if(!name.endsWith(".qss", Qt::CaseInsensitive))
+ name.append(".qss");
+
+ QString filePath = lthemeengine::userStyleSheetPath() + name;
+
+ if(QFile::exists(filePath))
+ {
+ QMessageBox::warning(this, tr("Error"), tr("The file \"%1\" already exists").arg(filePath));
+ return;
+ }
+
+ //creating empty file
+ QFile file(filePath);
+ file.open(QIODevice::WriteOnly);
+ file.close();
+
+ //creating item
+ QFileInfo info(filePath);
+ QListWidgetItem *item = new QListWidgetItem(info.fileName(), m_ui->qssListWidget);
+ item->setToolTip(info.filePath());
+ item->setData(QSS_FULL_PATH_ROLE, info.filePath());
+ item->setData(QSS_WRITABLE_ROLE, info.isWritable());
+ item->setCheckState(Qt::Unchecked);
+}
+
+void QSSPage::on_editButton_clicked()
+{
+ QListWidgetItem *item = m_ui->qssListWidget->currentItem();
+ if(item)
+ {
+ QSSEditorDialog dialog(item->data(QSS_FULL_PATH_ROLE).toString(), this);
+ dialog.exec();
+ }
+}
+
+void QSSPage::on_removeButton_clicked()
+{
+ QListWidgetItem *item = m_ui->qssListWidget->currentItem();
+ if(!item)
+ return;
+
+ int button = QMessageBox::question(this, tr("Confirm Remove"),
+ tr("Are you sure you want to remove style sheet \"%1\"?")
+ .arg(item->text()),
+ QMessageBox::Yes | QMessageBox::No);
+ if(button == QMessageBox::Yes)
+ {
+ QFile::remove(item->data(QSS_FULL_PATH_ROLE).toString());
+ delete item;
+ }
+}
+
+void QSSPage::readSettings()
+{
+ //load stylesheets
+ m_ui->qssListWidget->clear();
+ findStyleSheets(lthemeengine::userStyleSheetPath());
+ findStyleSheets(lthemeengine::sharedStyleSheetPath().join(", "));
+
+ QSettings settings(lthemeengine::configFile(), QSettings::IniFormat);
+ QStringList styleSheets = settings.value("Interface/stylesheets").toStringList();
+ for(int i = 0; i < m_ui->qssListWidget->count(); ++i)
+ {
+ QListWidgetItem *item = m_ui->qssListWidget->item(i);
+ if(styleSheets.contains(item->data(QSS_FULL_PATH_ROLE).toString()))
+ item->setCheckState(Qt::Checked);
+ else
+ item->setCheckState(Qt::Unchecked);
+ }
+}
+
+void QSSPage::findStyleSheets(const QString &path)
+{
+ QDir dir(path);
+ dir.setFilter(QDir::Files);
+ dir.setNameFilters(QStringList() << "*.qss");
+
+ foreach (QFileInfo info, dir.entryInfoList())
+ {
+ QListWidgetItem *item = new QListWidgetItem(info.fileName(), m_ui->qssListWidget);
+ item->setToolTip(info.filePath());
+ item->setData(QSS_FULL_PATH_ROLE, info.filePath());
+ item->setData(QSS_WRITABLE_ROLE, info.isWritable());
+ }
+}
+
+void QSSPage::on_renameButton_clicked()
+{
+ QListWidgetItem *item = m_ui->qssListWidget->currentItem();
+ if(!item)
+ return;
+
+ QString name = QInputDialog::getText(this, tr("Rename Style Sheet"), tr("Style sheet name:"),
+ QLineEdit::Normal, item->text(), 0);
+ if(name.isEmpty())
+ return;
+
+ if(!m_ui->qssListWidget->findItems(name, Qt::MatchExactly).isEmpty())
+ {
+ QMessageBox::warning(this, tr("Error"), tr("The style sheet \"%1\" already exists").arg(name));
+ return;
+ }
+
+ if(!name.endsWith(".qss", Qt::CaseInsensitive))
+ name.append(".qss");
+
+ QString newPath = lthemeengine::userStyleSheetPath() + name;
+
+ if(!QFile::rename(item->data(QSS_FULL_PATH_ROLE).toString(), newPath))
+ {
+ QMessageBox::warning(this, tr("Error"), tr("Unable to rename file"));
+ return;
+ }
+
+ item->setText(name);
+ item->setData(QSS_FULL_PATH_ROLE, newPath);
+ item->setToolTip(newPath);
+}
+
+void QSSPage::on_qssListWidget_customContextMenuRequested(const QPoint &pos)
+{
+ QListWidgetItem *item = m_ui->qssListWidget->currentItem();
+ if(item && item->data(QSS_WRITABLE_ROLE).toBool())
+ {
+ m_menu->exec(m_ui->qssListWidget->viewport()->mapToGlobal(pos));
+ }
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.h
new file mode 100644
index 00000000..665f68c0
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef QSSPAGE_H
+#define QSSPAGE_H
+
+#include "tabpage.h"
+
+namespace Ui {
+class QSSPage;
+}
+
+class QListWidgetItem;
+class QMenu;
+
+class QSSPage : public TabPage
+{
+ Q_OBJECT
+
+public:
+ explicit QSSPage(QWidget *parent = 0);
+ ~QSSPage();
+
+ void writeSettings();
+
+private slots:
+ void on_qssListWidget_currentItemChanged(QListWidgetItem *current, QListWidgetItem *);
+ void on_createButton_clicked();
+ void on_editButton_clicked();
+ void on_removeButton_clicked();
+ void on_renameButton_clicked();
+ void on_qssListWidget_customContextMenuRequested(const QPoint &pos);
+
+private:
+ void readSettings();
+ void findStyleSheets(const QString &path);
+ Ui::QSSPage *m_ui;
+ QMenu *m_menu;
+};
+
+#endif // QSSPAGE_H
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.ui b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.ui
new file mode 100644
index 00000000..124b4dc6
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/qsspage.ui
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>QSSPage</class>
+ <widget class="QWidget" name="QSSPage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>483</width>
+ <height>320</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string notr="true">Style Sheet Editor</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="1" column="0">
+ <widget class="QPushButton" name="createButton">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="text">
+ <string>Create</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <widget class="QPushButton" name="removeButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="5">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>189</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="0" column="0" colspan="6">
+ <widget class="QListWidget" name="qssListWidget">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="alternatingRowColors">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QPushButton" name="editButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QPushButton" name="renameButton">
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Rename</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.cpp b/src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.cpp
new file mode 100644
index 00000000..251ce024
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.cpp
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "tabpage.h"
+
+TabPage::TabPage(QWidget *parent) : QWidget(parent)
+{
+}
diff --git a/src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.h b/src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.h
new file mode 100644
index 00000000..ac285054
--- /dev/null
+++ b/src-qt5/core/lumina-theme-engine/src/lthemeengine/tabpage.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2014-2017, Ilya Kotov <forkotov02@hotmail.ru>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TABPAGE_H
+#define TABPAGE_H
+
+#include <QWidget>
+
+class TabPage : public QWidget
+{
+ Q_OBJECT
+public:
+ explicit TabPage(QWidget *parent = 0);
+
+ virtual void writeSettings() = 0;
+};
+
+#endif // TABPAGE_H
bgstack15