diff --git a/app/bin/mytetra.qrc b/app/bin/mytetra.qrc index 60c0e471c..b2c5e1303 100644 --- a/app/bin/mytetra.qrc +++ b/app/bin/mytetra.qrc @@ -85,6 +85,13 @@ resource/standartconfig/any/conf.ini resource/standartconfig/any/editorconf.ini resource/standartconfig/any/stylesheet.css + resource/standartconfig/any/styles/dark/pic/branch-closed.png + resource/standartconfig/any/styles/dark/pic/branch-end.png + resource/standartconfig/any/styles/dark/pic/branch-more.png + resource/standartconfig/any/styles/dark/pic/branch-open.png + resource/standartconfig/any/styles/dark/pic/vline.png + resource/standartconfig/any/styles/dark/stylesheet.css + resource/standartconfig/any/styles/light/stylesheet.css resource/standartconfig/meego/conf.ini resource/standartconfig/meego/editorconf.ini resource/standartconfig/meego/stylesheet.css diff --git a/app/bin/resource/standartconfig/any/styles/dark/pic/branch-closed.png b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-closed.png new file mode 100644 index 000000000..d9eb4af45 Binary files /dev/null and b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-closed.png differ diff --git a/app/bin/resource/standartconfig/any/styles/dark/pic/branch-end.png b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-end.png new file mode 100644 index 000000000..169983640 Binary files /dev/null and b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-end.png differ diff --git a/app/bin/resource/standartconfig/any/styles/dark/pic/branch-more.png b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-more.png new file mode 100644 index 000000000..357010887 Binary files /dev/null and b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-more.png differ diff --git a/app/bin/resource/standartconfig/any/styles/dark/pic/branch-open.png b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-open.png new file mode 100644 index 000000000..a22b9f4f7 Binary files /dev/null and b/app/bin/resource/standartconfig/any/styles/dark/pic/branch-open.png differ diff --git a/app/bin/resource/standartconfig/any/styles/dark/pic/vline.png b/app/bin/resource/standartconfig/any/styles/dark/pic/vline.png new file mode 100644 index 000000000..b9f0a1540 Binary files /dev/null and b/app/bin/resource/standartconfig/any/styles/dark/pic/vline.png differ diff --git a/app/bin/resource/standartconfig/any/styles/dark/stylesheet.css b/app/bin/resource/standartconfig/any/styles/dark/stylesheet.css new file mode 100644 index 000000000..9e6ca5ddc --- /dev/null +++ b/app/bin/resource/standartconfig/any/styles/dark/stylesheet.css @@ -0,0 +1,169 @@ +QWidget { +font: 10pt 'DejaVu Sans'; + outline: 0; + color: white; + background-color: #373e4d; } +QWidget::item:hover { + color: white; + background: #383C4A; } +QWidget::item:selected { + color: white; + background: #383C4A; } +QWidget::item:selected:active { + color: white; + background: #2d2f36; } +QTreeView::item:open { + color: white; } +QComboBox::drop-down:hover{ + border-left-color: #ff80ff; } +QComboBox:hover{ + border: 1px solid #ff80ff; } +QToolTip { + border: 1px solid #80ff80; + padding: 2px; + border-radius: 5px; + color: white; + background: #373e4d; } +QTextEdit:focus, +QTreeView:focus, +QTableView:focus { + border: 1px solid #3e7c3e; } +QTextEdit { + border: 1px solid #2f343f; + color: white; + background: #404759; + selection-color: #ff80ff; + selection-background-color: #2d2f36; + } +QProgressBar { + border: solid; + color: grey; + background: #404759; + selection-background-color: #80ff80; } +QCheckBox { + color: grey; + font-weight: bold; + border: 0px solid grey; } +QCheckBox::indicator { + width: 0px; + background-color: transparent; } +QCheckBox:unchecked { + color: gray; + background: #373e4d; } +QCheckBox:checked { + color: #80ffff; } +QToolBar, +QLabel, +QMenuBar, +QDialog, +QComboBox{ + border-style: solid; + color: #80ff80; + background: #373e4d; } +QComboBox:editable { + background: #404759; } +QComboBox { + border: 1px solid gray; + border-radius: 3px; + padding: 1px 18px 1px 3px; + min-width: 6em; } +QComboBox:!editable, +QComboBox::drop-down:editable { + background: #373e4d; } +QComboBox::drop-down { + width: 15px; + border-left-width: 1px; + border-left-color: darkgray; + border-left-style: solid; + border-top-right-radius: 3px; + border-bottom-right-radius: 3px; } +QLineEdit { + border: 1px solid grey; + background: #404759; } +QLineEdit:hover, +QLineEdit:focus { + border: 1px solid #80ff80; } +QPushButton:disabled{ + color: grey; + background-color: #373e4d; } +QPushButton { + background-color: #373e4d; + color: #80ff80; + font-weight: bold; + border-style: solid; + padding: 5px; } +QToolButton { + background-color: #373e4d; + font-weight: bold; + border-style: solid; + padding: 5px; } +QToolButton::hover, +QToolButton:checked { + background-color: #404759; } +QToolButton::pressed { + background-color: #2d2f36; } +QToolBar { + icon-size: 14px; + padding: 1; } +QTreeView::item, +QTableView { + border: 1px solid #2f343f; + color: white; + background: #404759; +} +QTableView QTableCornerButton::section, +QHeaderView::section:horizontal { + color: #5bf235; + border-style: solid; + height: 18px; + padding: 0px 3px 0px 6px; + background: #2f343f; } +QHeaderView::section:vertical { + color: #5bf235; + border-style: solid; + width: 18px; + padding: 0px 3px 0px 6px; + background: #373e4d; } +QTreeView::item { + border: 0px solid #2f343f; } +QTreeView { + border: 1px solid #2f343f; + color: #5bf235; + background: #404759; + selection-background-color: transparent; } +QTreeView::branch:has-siblings:!adjoins-item { + border-image: url(style/pic/vline.png) 0; } +QTreeView::branch:has-siblings:adjoins-item { + border-image: url(style/pic/branch-more.png) 0; } +QTreeView::branch:!has-children:!has-siblings:adjoins-item { + border-image: url(style/pic/branch-end.png) 0; } +QTreeView::branch:closed:has-children:has-siblings, +QTreeView::branch:has-children:!has-siblings:closed { + border-image: none; + image: url(style/pic/branch-closed.png); } +QTreeView::branch:open:has-children:!has-siblings, +QTreeView::branch:open:has-children:has-siblings{ + border-image: none; + image: url(style/pic/branch-open.png); } +QScrollBar:horizontal, +QScrollBar:vertical { + background-color: transparent; + height: 8px; + width: 8px; + margin: 0px; + padding: 0px; } +QScrollBar::handle:horizontal, +QScrollBar::handle:vertical { + border: none; + min-width: 100px; + background-color: #2b2f36; } +QScrollBar::add-line:horizontal, +QScrollBar::sub-line:horizontal, +QScrollBar::add-page:horizontal, +QScrollBar::sub-page:horizontal, +QScrollBar::add-line:vertical, +QScrollBar::sub-line:vertical, +QScrollBar::add-page:vertical, +QScrollBar::sub-page:vertical { + width: 0px; + background-color: transparent; } diff --git a/app/bin/resource/standartconfig/any/styles/light/stylesheet.css b/app/bin/resource/standartconfig/any/styles/light/stylesheet.css new file mode 100644 index 000000000..cc34ad08f --- /dev/null +++ b/app/bin/resource/standartconfig/any/styles/light/stylesheet.css @@ -0,0 +1,13 @@ +/* CSS style for any desktop OS */ +/* Set your Qt CSS style in this file */ + +QToolBar, QToolButton, QPushButton +{ + icon-size: 16px; /* maximum icon size */ +} + +/* +QToolButton { + padding: 0; +} +*/ diff --git a/app/bin/resource/translations/mytetra_ru.ts b/app/bin/resource/translations/mytetra_ru.ts index 2fb37aed5..ecf451176 100644 --- a/app/bin/resource/translations/mytetra_ru.ts +++ b/app/bin/resource/translations/mytetra_ru.ts @@ -274,7 +274,42 @@ Please enable action logging in Tools -> Preferences -> Misc Misc - Разное + + AppConfigPage_Appearance + + + Interface theme + Тема + + + + Light + Светлая + + + + Dark + Темная + + + + Run MyTetra in a minimized window + Запускать MyTetra в свернутом окне + + + + Hide detached windows if close main window + Сворачивать открепляемые окна при закрытии главного окна + + + + Interface + Интерфейс + + + + Windows behavior + Поведение diff --git a/app/src/libraries/GlobalParameters.cpp b/app/src/libraries/GlobalParameters.cpp index 94c5bf3fe..6cc6f2ccd 100644 --- a/app/src/libraries/GlobalParameters.cpp +++ b/app/src/libraries/GlobalParameters.cpp @@ -21,6 +21,7 @@ #include "libraries/WindowSwitcher.h" #include "libraries/FixedParameters.h" #include "libraries/helpers/DebugHelper.h" +#include "libraries/helpers/DiskHelper.h" #ifdef Q_OS_WIN32 #include "windows.h" @@ -268,11 +269,23 @@ void GlobalParameters::createFirstProgramFiles(QString dirName) } -void GlobalParameters::createStyleSheetFile(QString dirName) +void GlobalParameters::createStyleSheetFile(QString dirName, QString themeName) { QString targetOs=getTargetOs(); - QFile::copy(":/resource/standartconfig/"+targetOs+"/stylesheet.css", dirName+"/stylesheet.css"); - QFile::setPermissions(dirName+"/stylesheet.css", QFile::ReadUser | QFile::WriteUser); + if (targetOs == "any" && !themeName.isNull() && !themeName.isEmpty()) + { + QString fromDir=":/resource/standartconfig/any/styles/"+themeName; + QString toDir=dirName+"/style"; + DiskHelper::removeDirectory(toDir); + DiskHelper::copyDirectoryRecursively(fromDir, toDir, QFile::ReadUser | QFile::WriteUser); + } + else + { + QDir styleDir(dirName); + styleDir.mkdir("style"); + QFile::copy(":/resource/standartconfig/"+targetOs+"/stylesheet.css", dirName+"/style/stylesheet.css"); + QFile::setPermissions(dirName+"/style/stylesheet.css", QFile::ReadUser | QFile::WriteUser); + } } diff --git a/app/src/libraries/GlobalParameters.h b/app/src/libraries/GlobalParameters.h index dc27d39d1..42a151e27 100644 --- a/app/src/libraries/GlobalParameters.h +++ b/app/src/libraries/GlobalParameters.h @@ -64,7 +64,7 @@ class GlobalParameters : public QObject // Файл стилей может создаваться и после развертывания начальных файлов MyTetra // Так как в более старых версиях MyTetra его еще не было - void createStyleSheetFile(QString dirName); + void createStyleSheetFile(QString dirName, QString themeName=NULL); public: // Указание на обрабатываемую панель инструментов редактора текста diff --git a/app/src/libraries/helpers/CssHelper.cpp b/app/src/libraries/helpers/CssHelper.cpp index 5312338f8..a28f75d10 100644 --- a/app/src/libraries/helpers/CssHelper.cpp +++ b/app/src/libraries/helpers/CssHelper.cpp @@ -7,9 +7,11 @@ #include "CssHelper.h" #include "libraries/GlobalParameters.h" +#include "models/appConfig/AppConfig.h" extern GlobalParameters globalParameters; +extern AppConfig mytetraConfig; CssHelper::CssHelper() @@ -54,7 +56,18 @@ QString CssHelper::replaceCssMetaIconSize(QString styleText) void CssHelper::setCssStyle() { - QString csspath = globalParameters.getWorkDirectory()+"/stylesheet.css"; + QString dirName=globalParameters.getWorkDirectory(); + + // Если файл стилей есть по старому пути, переносим его в каталог style + QFile file(dirName+"/stylesheet.css"); + if (file.exists()) + { + QDir styleDir(dirName); + styleDir.mkdir("style"); + file.rename(dirName+"/style/stylesheet.css"); + } + + QString csspath = dirName+"/style/stylesheet.css"; QFile css(csspath); @@ -64,7 +77,14 @@ void CssHelper::setCssStyle() if(!openResult) { qDebug() << "Stylesheet not found in " << csspath << ". Create new css file."; - globalParameters.createStyleSheetFile( globalParameters.getWorkDirectory() ); + + QString themeName; + switch (mytetraConfig.getInterfaceTheme()) + { + case AppConfig::Light: themeName="light"; break; + case AppConfig::Dark: themeName="dark"; break; + } + globalParameters.createStyleSheetFile( globalParameters.getWorkDirectory(), themeName); } css.close(); diff --git a/app/src/libraries/helpers/DiskHelper.cpp b/app/src/libraries/helpers/DiskHelper.cpp index 4ec526ec6..526b60d22 100644 --- a/app/src/libraries/helpers/DiskHelper.cpp +++ b/app/src/libraries/helpers/DiskHelper.cpp @@ -187,6 +187,32 @@ bool DiskHelper::copyDirectory(const QString &fromName, const QString &toName) } +// Копирование содержимого директории +// Рекурсивно вместе с подкаталогами +bool DiskHelper::copyDirectoryRecursively(const QString &fromName, const QString &toName, QFile::Permissions permissionSpec) +{ + QDir fromDir(fromName); + if (!fromDir.exists()) + return false; + QDir toDir(toName); + if (!toDir.exists()) + toDir.mkpath("."); + + foreach (QString dirName, fromDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) { + QString destPath = toName + QDir::separator() + dirName; + fromDir.mkpath(destPath); + copyDirectoryRecursively(fromName+ QDir::separator() + dirName, destPath, permissionSpec); + } + + foreach (QString fileName, fromDir.entryList(QDir::Files)) { + QString destPath = toName + QDir::separator() + fileName; + QFile::copy(fromName + QDir::separator() + fileName, destPath); + QFile::setPermissions(destPath, permissionSpec); + } + return true; +} + + // Получение списка файлов с их содержимым в указанной директории QMap DiskHelper::getFilesFromDirectory(QString dirName, QString fileMask) { diff --git a/app/src/libraries/helpers/DiskHelper.h b/app/src/libraries/helpers/DiskHelper.h index 6e12f6b35..5eddaca00 100644 --- a/app/src/libraries/helpers/DiskHelper.h +++ b/app/src/libraries/helpers/DiskHelper.h @@ -1,6 +1,7 @@ #ifndef DISKHELPER_H #define DISKHELPER_H +#include #include #include #include @@ -19,6 +20,7 @@ class DiskHelper static QString createTempDirectory(void); static bool removeDirectory(const QString &dirName); static bool copyDirectory(const QString &fromName, const QString &toName); + static bool copyDirectoryRecursively(const QString &fromName, const QString &toName, QFile::Permissions permissionSpec); static QMap getFilesFromDirectory(QString dirName, QString fileMask); static bool saveFilesToDirectory(QString dirName, QMap fileList); diff --git a/app/src/models/appConfig/AppConfig.cpp b/app/src/models/appConfig/AppConfig.cpp index 5cc27d700..7762c11c1 100644 --- a/app/src/models/appConfig/AppConfig.cpp +++ b/app/src/models/appConfig/AppConfig.cpp @@ -963,6 +963,30 @@ void AppConfig::setDockableWindowsBehavior(QString mode) } +// Тема оформления +AppConfig::InterfaceTheme AppConfig::getInterfaceTheme() +{ + QString themeName = get_parameter("theme"); + + InterfaceTheme theme; + if (themeName == "dark") theme=InterfaceTheme::Dark; + else theme=InterfaceTheme::Light; + + return theme; +} + +void AppConfig::setInterfaceTheme(InterfaceTheme theme) +{ + QString themeName; + switch (theme) + { + case InterfaceTheme::Light: themeName="light"; break; + case InterfaceTheme::Dark: themeName="dark"; break; + } + conf->setValue("theme", themeName); +} + + // -------------------- // Номер версии конфига // -------------------- @@ -1127,6 +1151,7 @@ void AppConfig::update_version_process(void) parameterFunctions << &AppConfig::get_parameter_table_36; parameterFunctions << &AppConfig::get_parameter_table_37; parameterFunctions << &AppConfig::get_parameter_table_38; + parameterFunctions << &AppConfig::get_parameter_table_39; for(int i=1; i #include #include #include "AppConfigPage_Appearance.h" + #include "models/appConfig/AppConfig.h" #include "libraries/GlobalParameters.h" +#include "libraries/helpers/DiskHelper.h" #include "libraries/wyedit/EditorShowTextDispatcher.h" @@ -29,6 +32,16 @@ void AppConfigPage_Appearance::setupUi() { qDebug() << "Create appearance config page"; + // Выбор темы интерфейса + themeLabel=new QLabel(this); + themeLabel->setText(tr("Interface theme")); + + theme=new MtComboBox(this); + theme->setMinimumContentsLength(2); + theme->addItem(tr("Light")); + theme->addItem(tr("Dark")); + theme->setCurrentIndex((int)mytetraConfig.getInterfaceTheme()); + // Настройка запуска MyTetra в свернутом окне runInMinimizedWindow=new QCheckBox(this); runInMinimizedWindow->setText(tr("Run MyTetra in a minimized window")); @@ -50,6 +63,21 @@ void AppConfigPage_Appearance::setupSignals() void AppConfigPage_Appearance::assembly() { + // Группировщик настроек интерфейса + interfaceBox=new QGroupBox(this); + interfaceBox->setTitle(tr("Interface")); + + // Выбор темы + QHBoxLayout *themeLayout=new QHBoxLayout(); + themeLayout->addWidget(theme); + + // Виджеты вставляются в группировщик настроек курсора при навигации по истории + QGridLayout *interfaceLayout = new QGridLayout; + interfaceLayout->addWidget(themeLabel,0,0); + interfaceLayout->addLayout(themeLayout,0,1); + interfaceLayout->setColumnStretch(1,100); + interfaceBox->setLayout(interfaceLayout); + // Группировщик виджетов настройки поведения окна behaviorBox=new QGroupBox(this); behaviorBox->setTitle(tr("Windows behavior")); @@ -62,6 +90,7 @@ void AppConfigPage_Appearance::assembly() // Собирается основной слой QVBoxLayout *centralLayout=new QVBoxLayout(); + centralLayout->addWidget(interfaceBox); centralLayout->addWidget(behaviorBox); centralLayout->addStretch(); @@ -79,6 +108,18 @@ int AppConfigPage_Appearance::applyChanges() int result=0; + // Если был изменена тема + if(mytetraConfig.getInterfaceTheme()!=theme->currentIndex()) + { + mytetraConfig.setInterfaceTheme((AppConfig::InterfaceTheme)theme->currentIndex()); + + // Удаляем существующий стиль, чтобы при следующем запуске установить новый + QString dirName=globalParameters.getWorkDirectory(); + DiskHelper::removeDirectory(dirName+"/style"); + + result=1; + } + // Сохраняется настройка режима запуска MyTetra - обычный или свернутый if(mytetraConfig.get_runinminimizedwindow()!=runInMinimizedWindow->isChecked()) { diff --git a/app/src/views/appConfigWindow/AppConfigPage_Appearance.h b/app/src/views/appConfigWindow/AppConfigPage_Appearance.h index b17d2db4e..fa523ef10 100644 --- a/app/src/views/appConfigWindow/AppConfigPage_Appearance.h +++ b/app/src/views/appConfigWindow/AppConfigPage_Appearance.h @@ -4,12 +4,16 @@ #include #include #include +#include #include "ConfigPage.h" +#include "libraries/MtComboBox.h" class AppConfigPage_Appearance : public ConfigPage { + Q_OBJECT + public: AppConfigPage_Appearance(QWidget *parent = nullptr); virtual ~AppConfigPage_Appearance(); @@ -24,6 +28,10 @@ class AppConfigPage_Appearance : public ConfigPage // Объединяющая рамка QGroupBox *behaviorBox; + QGroupBox *interfaceBox; + + QLabel *themeLabel; + MtComboBox *theme; QCheckBox *runInMinimizedWindow; // Разрешен ли запуск в свернутом окне QCheckBox *dockableWindowsBehavior; // Поведение открепляемых окон