diff options
Diffstat (limited to 'src-qt5/core/lumina-theme-engine/src')
45 files changed, 4629 insertions, 0 deletions
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 ¶ms); +}; + +QPlatformTheme *lthemeenginePlatformThemePlugin::create(const QString &key, const QStringList ¶ms) +{ + 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 |