From 0fe852630db4d8b3cb02bcad94be0c491bd94372 Mon Sep 17 00:00:00 2001 From: Kubat <mael.martin31@gmail.com> Date: Wed, 8 Sep 2021 11:49:02 +0200 Subject: [PATCH] UI: Import and modify QtCreator's theming system (simplify it a bit) --- CMakeLists.txt | 24 +- PreCompiledHeaders.cmake | 4 + src/UI/Theme/Theme.cc | 306 +++++++++++++++++++++++++ src/UI/Theme/Theme.hh | 475 +++++++++++++++++++++++++++++++++++++++ src/UI/Theme/ThemeMac.hh | 6 + src/UI/Theme/ThemeMac.mm | 21 ++ 6 files changed, 830 insertions(+), 6 deletions(-) create mode 100644 src/UI/Theme/Theme.cc create mode 100644 src/UI/Theme/Theme.hh create mode 100644 src/UI/Theme/ThemeMac.hh create mode 100644 src/UI/Theme/ThemeMac.mm diff --git a/CMakeLists.txt b/CMakeLists.txt index 498df5aa..bfa3728e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,6 +5,20 @@ project(Vivy VERSION 0.1 LANGUAGES CXX) cmake_policy(SET CMP0100 NEW) # Let cmake use moc and uic for .hh files cmake_policy(SET CMP0009 NEW) # Do not follow symlinks with GLOB_RECURSE +# Don't forget for specific things +if(WIN32) + message("You are building on windows, pay attenion to the dependencies") +endif() +if(MSVC OR MSYS OR MINGW) + message("You are building with a windows compiler") +endif() +if(APPLE) + message("You are building on MacOS X") +endif() +if(UNIX AND NOT APPLE) + message("You are building on Linux, FreeBSD or any other toaster OS") +endif() + # Pass -fPIC set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -20,11 +34,6 @@ set(THREADS_PREFER_PTHREAD_FLAG ON) find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED) find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED) -if(WIN32) - message("You are building on windows, pay attenion to the dependencies") - # Needed setup for Vivy to compile on Windows goes here -endif() - # Find others dependencies find_library(AVCODEC_LIBRARY avcodec 4.0 REQUIRED) find_library(AVUTIL_LIBRARY avutil 4.0 REQUIRED) @@ -41,7 +50,10 @@ add_subdirectory( # Grab all files file(GLOB_RECURSE Vivy_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.cc") file(GLOB_RECURSE Vivy_INC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.hh") -set(PROJECT_SOURCES ${Vivy_SRC} ${Vivy_INC}) +if(APPLE) + file(GLOB_RECURSE Vivy_APPLE_SRC CONFIGURE_DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/src/*.mm") +endif() +set(PROJECT_SOURCES ${Vivy_SRC} ${Vivy_INC} ${Vivy_APPLE_SRC}) # Add the Vivy executable if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) diff --git a/PreCompiledHeaders.cmake b/PreCompiledHeaders.cmake index b04fef69..f1d1768e 100644 --- a/PreCompiledHeaders.cmake +++ b/PreCompiledHeaders.cmake @@ -37,6 +37,7 @@ set(QT_STRUCT_INC PRIVATE <qglobal.h> <QThread> + <QOperatingSystemVersion> <QtGlobal> <QObject> <QRegularExpression> @@ -60,7 +61,9 @@ set(QT_STRUCT_INC <QList> <QVector> <QMap> + <QSettings> <QStringList> + <QMetaEnum> <QJsonObject> <QJsonArray> <QJsonDocument> @@ -72,6 +75,7 @@ set(QT_WIDGET_INC <QCoreApplication> <QTextDocument> <QColor> + <QPalette> <QWidget> <QIcon> <QFont> diff --git a/src/UI/Theme/Theme.cc b/src/UI/Theme/Theme.cc new file mode 100644 index 00000000..12d07e2b --- /dev/null +++ b/src/UI/Theme/Theme.cc @@ -0,0 +1,306 @@ +#include "Theme.hh" +#include "../../Lib/HostOsInfo.hh" +#ifdef Q_OS_MACOS +#import "ThemeMac.hh" +#endif + +namespace Vivy +{ +Theme::ThemePrivate::ThemePrivate() noexcept +{ + const QMetaObject &m = Theme::staticMetaObject; + colors.resize(m.enumerator(m.indexOfEnumerator("Color")).keyCount()); + imageFiles.resize(m.enumerator(m.indexOfEnumerator("ImageFile")).keyCount()); + gradients.resize(m.enumerator(m.indexOfEnumerator("Gradient")).keyCount()); + flags.resize(m.enumerator(m.indexOfEnumerator("Flag")).keyCount()); +} + +void +Theme::applyToApplication() const noexcept +{ +#ifdef Q_OS_MACOS + // Match the native UI theme and palette with the creator + // theme by forcing light aqua for light creator themes. + if (!flag(Theme::DarkUserInterface)) + Internal::forceMacOSLightAquaApperance(); +#endif + + // if (flag(Theme::ApplyThemePaletteGlobally)) + QApplication::setPalette(palette()); +} + +Theme::Theme(const QString &id, QObject *parent) noexcept + : QObject(parent) + , d(new ThemePrivate) +{ + d->id = id; +} + +Theme::~Theme() noexcept { delete d; } + +QStringList +Theme::preferredStyles() const noexcept +{ + return d->preferredStyles; +} + +QString +Theme::defaultTextEditorColorScheme() const noexcept +{ + return d->defaultTextEditorColorScheme; +} + +QString +Theme::id() const noexcept +{ + return d->id; +} + +bool +Theme::flag(Theme::Flag f) const noexcept +{ + return d->flags[f]; +} + +QColor +Theme::color(Theme::Color role) const noexcept +{ + return d->colors[role].first; +} + +QString +Theme::imageFile(Theme::ImageFile imageFile, const QString &fallBack) const noexcept +{ + const QString &file = d->imageFiles.at(imageFile); + return file.isEmpty() ? fallBack : file; +} + +QGradientStops +Theme::gradient(Theme::Gradient role) const noexcept +{ + return d->gradients[role]; +} + +QPair<QColor, QString> +Theme::readNamedColor(const QString &color) const +{ + if (d->palette.contains(color)) + return qMakePair(d->palette[color], color); + if (color == QLatin1String("style")) + return qMakePair(QColor(), QString()); + + const QColor col('#' + color); + if (!col.isValid()) { + qWarning("Color \"%s\" is neither a named color nor a valid color", qPrintable(color)); + return qMakePair(Qt::black, QString()); + } + return qMakePair(col, QString()); +} + +QString +Theme::filePath() const noexcept +{ + return d->fileName; +} + +QString +Theme::displayName() const noexcept +{ + return d->displayName; +} + +void +Theme::setDisplayName(const QString &name) noexcept +{ + d->displayName = name; +} + +void +Theme::readSettings(QSettings *const settings) noexcept +{ + d->fileName = settings->fileName(); + const QMetaObject &m = *metaObject(); + + { + d->displayName = + settings->value(QLatin1String("ThemeName"), QLatin1String("unnamed")).toString(); + d->preferredStyles = settings->value(QLatin1String("PreferredStyles")).toStringList(); + d->preferredStyles.removeAll(QString()); + d->defaultTextEditorColorScheme = + settings->value(QLatin1String("DefaultTextEditorColorScheme")).toString(); + } + { + settings->beginGroup(QLatin1String("Palette")); + const QStringList allKeys = settings->allKeys(); + for (const QString &key : allKeys) + d->palette[key] = readNamedColor(settings->value(key).toString()).first; + settings->endGroup(); + } + { + settings->beginGroup(QLatin1String("Colors")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("Color")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + if (!settings->contains(key)) { + if (i < PaletteWindow || i > PalettePlaceholderTextDisabled) + qWarning("Theme \"%s\" misses color setting for key \"%s\".", + qPrintable(d->fileName), qPrintable(key)); + continue; + } + d->colors[i] = readNamedColor(settings->value(key).toString()); + } + settings->endGroup(); + } + { + settings->beginGroup(QLatin1String("ImageFiles")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("ImageFile")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + d->imageFiles[i] = settings->value(key).toString(); + } + settings->endGroup(); + } + { + settings->beginGroup(QLatin1String("Gradients")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("Gradient")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + QGradientStops stops; + int size = settings->beginReadArray(key); + for (int j = 0; j < size; ++j) { + settings->setArrayIndex(j); + TODO(Assert things when needed !); + settings->contains(QLatin1String("pos")); // TODO: Assert it + const double pos = settings->value(QLatin1String("pos")).toDouble(); + settings->contains(QLatin1String("color")); // TODO: Assert it + const QColor c('#' + settings->value(QLatin1String("color")).toString()); + stops.append(qMakePair(pos, c)); + } + settings->endArray(); + d->gradients[i] = stops; + } + settings->endGroup(); + } + { + settings->beginGroup(QLatin1String("Flags")); + QMetaEnum e = m.enumerator(m.indexOfEnumerator("Flag")); + for (int i = 0, total = e.keyCount(); i < total; ++i) { + const QString key = QLatin1String(e.key(i)); + TODO(Assert it); + settings->contains(key); // TODO: Assert it! + d->flags[i] = settings->value(key).toBool(); + } + settings->endGroup(); + } +} + +bool +Theme::systemUsesDarkMode() noexcept +{ + if (Utils::HostOsInfo::isWindowsHost()) { + constexpr char regkey[] = + "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; + bool ok; + const auto setting = + QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok); + return ok && setting == 0; + } else if (Utils::HostOsInfo::isMacHost()) { + return false; + } else if (Utils::HostOsInfo::isLinuxHost()) { + return true; + } + return false; +} + +// If you copy QPalette, default values stay at default, even if that default is different +// within the context of different widgets. Create deep copy. +static QPalette +copyPalette(const QPalette &p) noexcept +{ + QPalette res; + for (int group = 0; group < QPalette::NColorGroups; ++group) { + for (int role = 0; role < QPalette::NColorRoles; ++role) { + res.setBrush(QPalette::ColorGroup(group), QPalette::ColorRole(role), + p.brush(QPalette::ColorGroup(group), QPalette::ColorRole(role))); + } + } + return res; +} + +QPalette +Theme::initialPalette() noexcept +{ + static QPalette palette = copyPalette(QApplication::palette()); + return palette; +} + +QPalette +Theme::palette() const noexcept +{ + QPalette pal = initialPalette(); + // if (!flag(DerivePaletteFromTheme)) + // return pal; + + const static struct { + Color themeColor; + QPalette::ColorRole paletteColorRole; + QPalette::ColorGroup paletteColorGroup; + bool setColorRoleAsBrush; + } mapping[] = { + { PaletteWindow, QPalette::Window, QPalette::All, false }, + { PaletteWindowDisabled, QPalette::Window, QPalette::Disabled, false }, + { PaletteWindowText, QPalette::WindowText, QPalette::All, true }, + { PaletteWindowTextDisabled, QPalette::WindowText, QPalette::Disabled, true }, + { PaletteBase, QPalette::Base, QPalette::All, false }, + { PaletteBaseDisabled, QPalette::Base, QPalette::Disabled, false }, + { PaletteAlternateBase, QPalette::AlternateBase, QPalette::All, false }, + { PaletteAlternateBaseDisabled, QPalette::AlternateBase, QPalette::Disabled, false }, + { PaletteToolTipBase, QPalette::ToolTipBase, QPalette::All, true }, + { PaletteToolTipBaseDisabled, QPalette::ToolTipBase, QPalette::Disabled, true }, + { PaletteToolTipText, QPalette::ToolTipText, QPalette::All, false }, + { PaletteToolTipTextDisabled, QPalette::ToolTipText, QPalette::Disabled, false }, + { PaletteText, QPalette::Text, QPalette::All, true }, + { PaletteTextDisabled, QPalette::Text, QPalette::Disabled, true }, + { PaletteButton, QPalette::Button, QPalette::All, false }, + { PaletteButtonDisabled, QPalette::Button, QPalette::Disabled, false }, + { PaletteButtonText, QPalette::ButtonText, QPalette::All, true }, + { PaletteButtonTextDisabled, QPalette::ButtonText, QPalette::Disabled, true }, + { PaletteBrightText, QPalette::BrightText, QPalette::All, false }, + { PaletteBrightTextDisabled, QPalette::BrightText, QPalette::Disabled, false }, + { PaletteHighlight, QPalette::Highlight, QPalette::All, true }, + { PaletteHighlightDisabled, QPalette::Highlight, QPalette::Disabled, true }, + { PaletteHighlightedText, QPalette::HighlightedText, QPalette::All, true }, + { PaletteHighlightedTextDisabled, QPalette::HighlightedText, QPalette::Disabled, true }, + { PaletteLink, QPalette::Link, QPalette::All, false }, + { PaletteLinkDisabled, QPalette::Link, QPalette::Disabled, false }, + { PaletteLinkVisited, QPalette::LinkVisited, QPalette::All, false }, + { PaletteLinkVisitedDisabled, QPalette::LinkVisited, QPalette::Disabled, false }, + { PaletteLight, QPalette::Light, QPalette::All, false }, + { PaletteLightDisabled, QPalette::Light, QPalette::Disabled, false }, + { PaletteMidlight, QPalette::Midlight, QPalette::All, false }, + { PaletteMidlightDisabled, QPalette::Midlight, QPalette::Disabled, false }, + { PaletteDark, QPalette::Dark, QPalette::All, false }, + { PaletteDarkDisabled, QPalette::Dark, QPalette::Disabled, false }, + { PaletteMid, QPalette::Mid, QPalette::All, false }, + { PaletteMidDisabled, QPalette::Mid, QPalette::Disabled, false }, + { PaletteShadow, QPalette::Shadow, QPalette::All, false }, + { PaletteShadowDisabled, QPalette::Shadow, QPalette::Disabled, false }, + { PalettePlaceholderText, QPalette::PlaceholderText, QPalette::All, false }, + { PalettePlaceholderTextDisabled, QPalette::PlaceholderText, QPalette::Disabled, false }, + }; + + for (auto entry : mapping) { + const QColor themeColor = color(entry.themeColor); + // Use original color if color is not defined in theme. + if (themeColor.isValid()) { + if (entry.setColorRoleAsBrush) + // TODO: Find out why sometimes setBrush is used + pal.setBrush(entry.paletteColorGroup, entry.paletteColorRole, themeColor); + else + pal.setColor(entry.paletteColorGroup, entry.paletteColorRole, themeColor); + } + } + + return pal; +} +} diff --git a/src/UI/Theme/Theme.hh b/src/UI/Theme/Theme.hh new file mode 100644 index 00000000..86a3dc48 --- /dev/null +++ b/src/UI/Theme/Theme.hh @@ -0,0 +1,475 @@ +#pragma once + +// #include "../../Lib/Log.hh" + +namespace Vivy +{ +class ThemePrivate; +class Theme; + +class Theme final : public QObject { + Q_OBJECT + + struct ThemePrivate final { + ThemePrivate() noexcept; + + QString id; + QString fileName; + QString displayName; + QStringList preferredStyles; + QString defaultTextEditorColorScheme; + QVector<QPair<QColor, QString>> colors; + QVector<QString> imageFiles; + QVector<QGradientStops> gradients; + QVector<bool> flags; + QMap<QString, QColor> palette; + }; + +public: + Theme(const QString &id, QObject *parent = nullptr) noexcept; + ~Theme() noexcept override; + + void applyToApplication() const noexcept; + + enum Color { + BackgroundColorAlternate, + BackgroundColorDark, + BackgroundColorHover, + BackgroundColorNormal, + BackgroundColorSelected, + BackgroundColorDisabled, + BadgeLabelBackgroundColorChecked, + BadgeLabelBackgroundColorUnchecked, + BadgeLabelTextColorChecked, + BadgeLabelTextColorUnchecked, + CanceledSearchTextColor, + ComboBoxArrowColor, + ComboBoxArrowColorDisabled, + ComboBoxTextColor, + DetailsButtonBackgroundColorHover, + DetailsWidgetBackgroundColor, + DockWidgetResizeHandleColor, + DoubleTabWidget1stSeparatorColor, + DoubleTabWidget1stTabActiveTextColor, + DoubleTabWidget1stTabBackgroundColor, + DoubleTabWidget1stTabInactiveTextColor, + DoubleTabWidget2ndSeparatorColor, + DoubleTabWidget2ndTabActiveTextColor, + DoubleTabWidget2ndTabBackgroundColor, + DoubleTabWidget2ndTabInactiveTextColor, + EditorPlaceholderColor, + FancyToolBarSeparatorColor, + FancyTabBarBackgroundColor, + FancyTabBarSelectedBackgroundColor, + FancyTabWidgetDisabledSelectedTextColor, + FancyTabWidgetDisabledUnselectedTextColor, + FancyTabWidgetEnabledSelectedTextColor, + FancyTabWidgetEnabledUnselectedTextColor, + FancyToolButtonHoverColor, + FancyToolButtonSelectedColor, + FutureProgressBackgroundColor, + InfoBarBackground, + InfoBarText, // TODO: Deprecate. Unused. + MenuBarEmptyAreaBackgroundColor, + MenuBarItemBackgroundColor, + MenuBarItemTextColorDisabled, + MenuBarItemTextColorNormal, + MenuItemTextColorDisabled, + MenuItemTextColorNormal, + MiniProjectTargetSelectorBackgroundColor, // TODO: Deprecate. -> Utils::StyleHelper().baseColor() + MiniProjectTargetSelectorBorderColor, + MiniProjectTargetSelectorSummaryBackgroundColor, // TODO: Deprecate. -> Utils::StyleHelper().baseColor() + MiniProjectTargetSelectorTextColor, + OutputPaneButtonFlashColor, + OutputPaneToggleButtonTextColorChecked, + OutputPaneToggleButtonTextColorUnchecked, + PanelStatusBarBackgroundColor, + PanelsWidgetSeparatorLineColor, // TODO: Deprecate. Unused. + PanelTextColorDark, + PanelTextColorMid, + PanelTextColorLight, + ProgressBarColorError, + ProgressBarColorFinished, + ProgressBarColorNormal, + ProgressBarTitleColor, + ProgressBarBackgroundColor, + SplitterColor, + TextColorDisabled, + TextColorError, + TextColorHighlight, + TextColorHighlightBackground, + TextColorLink, + TextColorLinkVisited, + TextColorNormal, + ToggleButtonBackgroundColor, + ToolBarBackgroundColor, + TreeViewArrowColorNormal, + TreeViewArrowColorSelected, + + /* Palette for QPalette */ + + PaletteWindow, + PaletteWindowText, + PaletteBase, + PaletteAlternateBase, + PaletteToolTipBase, + PaletteToolTipText, + PaletteText, + PaletteButton, + PaletteButtonText, + PaletteBrightText, + PaletteHighlight, + PaletteHighlightedText, + PaletteLink, + PaletteLinkVisited, + + PaletteLight, + PaletteMidlight, + PaletteDark, + PaletteMid, + PaletteShadow, + + PaletteWindowDisabled, + PaletteWindowTextDisabled, + PaletteBaseDisabled, + PaletteAlternateBaseDisabled, + PaletteToolTipBaseDisabled, + PaletteToolTipTextDisabled, + PaletteTextDisabled, + PaletteButtonDisabled, + PaletteButtonTextDisabled, + PaletteBrightTextDisabled, + PaletteHighlightDisabled, + PaletteHighlightedTextDisabled, + PaletteLinkDisabled, + PaletteLinkVisitedDisabled, + + PaletteLightDisabled, + PaletteMidlightDisabled, + PaletteDarkDisabled, + PaletteMidDisabled, + PaletteShadowDisabled, + + PalettePlaceholderText, + PalettePlaceholderTextDisabled, + + /* Icons */ + + IconsBaseColor, + IconsDisabledColor, + IconsInfoColor, + IconsInfoToolBarColor, + IconsWarningColor, + IconsWarningToolBarColor, + IconsErrorColor, + IconsErrorToolBarColor, + IconsRunColor, + IconsRunToolBarColor, + IconsStopColor, + IconsStopToolBarColor, + IconsInterruptColor, + IconsInterruptToolBarColor, + IconsDebugColor, + IconsNavigationArrowsColor, + IconsBuildHammerHandleColor, + IconsBuildHammerHeadColor, + IconsModeWelcomeActiveColor, + IconsModeEditActiveColor, + IconsModeDesignActiveColor, + IconsModeDebugActiveColor, + IconsModeProjectActiveColor, + IconsModeAnalyzeActiveColor, + IconsModeHelpActiveColor, + + /* Code model Icons */ + + IconsCodeModelKeywordColor, + IconsCodeModelClassColor, + IconsCodeModelStructColor, + IconsCodeModelFunctionColor, + IconsCodeModelVariableColor, + IconsCodeModelEnumColor, + IconsCodeModelMacroColor, + IconsCodeModelAttributeColor, + IconsCodeModelUniformColor, + IconsCodeModelVaryingColor, + IconsCodeModelOverlayBackgroundColor, + IconsCodeModelOverlayForegroundColor, + + /* Code model text marks */ + + CodeModel_Error_TextMarkColor, + CodeModel_Warning_TextMarkColor, + + /* Output panes */ + + OutputPanes_DebugTextColor, + OutputPanes_ErrorMessageTextColor, + OutputPanes_MessageOutput, + OutputPanes_NormalMessageTextColor, + OutputPanes_StdErrTextColor, + OutputPanes_StdOutTextColor, + OutputPanes_WarningMessageTextColor, + OutputPanes_TestPassTextColor, + OutputPanes_TestFailTextColor, + OutputPanes_TestXFailTextColor, + OutputPanes_TestXPassTextColor, + OutputPanes_TestSkipTextColor, + OutputPanes_TestWarnTextColor, + OutputPanes_TestFatalTextColor, + OutputPanes_TestDebugTextColor, + + /* Debugger Log Window */ + + Debugger_LogWindow_LogInput, + Debugger_LogWindow_LogStatus, + Debugger_LogWindow_LogTime, + + /* Debugger Watch Item */ + + Debugger_WatchItem_ValueNormal, + Debugger_WatchItem_ValueInvalid, + Debugger_WatchItem_ValueChanged, + + /* Welcome Plugin */ + + Welcome_TextColor, + Welcome_ForegroundPrimaryColor, + Welcome_ForegroundSecondaryColor, + Welcome_BackgroundColor, + Welcome_ButtonBackgroundColor, + Welcome_DividerColor, + Welcome_LinkColor, + Welcome_HoverColor, + Welcome_DisabledLinkColor, + + /* Timeline Library */ + Timeline_TextColor, + Timeline_BackgroundColor1, + Timeline_BackgroundColor2, + Timeline_DividerColor, + Timeline_HighlightColor, + Timeline_PanelBackgroundColor, + Timeline_PanelHeaderColor, + Timeline_HandleColor, + Timeline_RangeColor, + + /* VcsBase Plugin */ + VcsBase_FileStatusUnknown_TextColor, + VcsBase_FileAdded_TextColor, + VcsBase_FileModified_TextColor, + VcsBase_FileDeleted_TextColor, + VcsBase_FileRenamed_TextColor, + VcsBase_FileUnmerged_TextColor, + + /* Bookmarks Plugin */ + Bookmarks_TextMarkColor, + + /* TextEditor Plugin */ + TextEditor_SearchResult_ScrollBarColor, + TextEditor_CurrentLine_ScrollBarColor, + + /* Debugger Plugin */ + Debugger_Breakpoint_TextMarkColor, + + /* ProjectExplorer Plugin */ + ProjectExplorer_TaskError_TextMarkColor, + ProjectExplorer_TaskWarn_TextMarkColor, + + /* QmlDesigner Plugin */ + QmlDesigner_BackgroundColor, + QmlDesigner_HighlightColor, + QmlDesigner_FormEditorSelectionColor, + QmlDesigner_FormEditorForegroundColor, + QmlDesigner_BackgroundColorDarker, + QmlDesigner_BackgroundColorDarkAlternate, + QmlDesigner_TabLight, + QmlDesigner_TabDark, + QmlDesigner_ButtonColor, + QmlDesigner_BorderColor, + QmlDesigner_FormeditorBackgroundColor, + QmlDesigner_AlternateBackgroundColor, + QmlDesigner_ScrollBarHandleColor, + + /* Palette for DS Controls */ + + DSpanelBackground, + DSinteraction, + DSerrorColor, + DSdisabledColor, + DScontrolBackground, + DScontrolBackgroundInteraction, + DScontrolBackgroundDisabled, + DScontrolBackgroundGlobalHover, + DScontrolBackgroundHover, + DScontrolOutline, + DScontrolOutlineInteraction, + DScontrolOutlineDisabled, + DStextColor, + DStextColorDisabled, + DStextSelectionColor, + DStextSelectedTextColor, + + DSplaceholderTextColor, + DSplaceholderTextColorInteraction, + + DSiconColor, + DSiconColorHover, + DSiconColorInteraction, + DSiconColorDisabled, + DSiconColorSelected, + DSlinkIndicatorColor, + DSlinkIndicatorColorHover, + DSlinkIndicatorColorInteraction, + DSlinkIndicatorColorDisabled, + DSpopupBackground, + DSpopupOverlayColor, + DSsliderActiveTrack, + DSsliderActiveTrackHover, + DSsliderActiveTrackFocus, + DSsliderInactiveTrack, + DSsliderInactiveTrackHover, + DSsliderInactiveTrackFocus, + DSsliderHandle, + DSsliderHandleHover, + DSsliderHandleFocus, + DSsliderHandleInteraction, + DSscrollBarTrack, + DSscrollBarHandle, + DSsectionHeadBackground, + DSstateDefaultHighlight, + DSstateSeparatorColor, + DSstateBackgroundColor, + DSstatePreviewOutline, + DSchangedStateText, + DS3DAxisXColor, + DS3DAxisYColor, + DS3DAxisZColor, + DSactionBinding, + DSactionAlias, + DSactionKeyframe, + DSactionJIT, + + DStableHeaderBackground, + DStableHeaderText, + + DSdockContainerBackground, + DSdockContainerSplitter, + DSdockAreaBackground, + + DSdockWidgetBackground, + DSdockWidgetSplitter, + DSdockWidgetTitleBar, + + DStitleBarText, + DStitleBarIcon, + DStitleBarButtonHover, + DStitleBarButtonPress, + + DStabContainerBackground, + DStabSplitter, + + DStabInactiveBackground, + DStabInactiveText, + DStabInactiveIcon, + DStabInactiveButtonHover, + DStabInactiveButtonPress, + + DStabActiveBackground, + DStabActiveText, + DStabActiveIcon, + DStabActiveButtonHover, + DStabActiveButtonPress, + + DStabFocusBackground, + DStabFocusText, + DStabFocusIcon, + DStabFocusButtonHover, + DStabFocusButtonPress, + + DSnavigatorBranch, + DSnavigatorBranchIndicator, + DSnavigatorItemBackground, + DSnavigatorItemBackgroundHover, + DSnavigatorItemBackgroundSelected, + DSnavigatorText, + DSnavigatorTextHover, + DSnavigatorTextSelected, + DSnavigatorIcon, + DSnavigatorIconHover, + DSnavigatorIconSelected, + DSnavigatorAliasIconChecked, + DSnavigatorDropIndicatorBackground, + DSnavigatorDropIndicatorOutline, + + DSheaderViewBackground, + DStableViewAlternateBackground, + + DStoolTipBackground, + DStoolTipOutline, + DStoolTipText, + + DSUnimportedModuleColor + }; + + enum Gradient { + DetailsWidgetHeaderGradient, + }; + + enum ImageFile { + IconOverlayCSource, + IconOverlayCppHeader, + IconOverlayCppSource, + IconOverlayPri, + IconOverlayPrf, + IconOverlayPro, + StandardPixmapFileIcon, + StandardPixmapDirIcon + }; + + enum Flag { + DrawTargetSelectorBottom, + DrawSearchResultWidgetFrame, + DrawIndicatorBranch, + DrawToolBarHighlights, + DrawToolBarBorders, + ComboBoxDrawTextShadow, + DerivePaletteFromTheme, + ApplyThemePaletteGlobally, + FlatToolBars, + FlatSideBarIcons, + FlatProjectsMode, + FlatMenuBar, + ToolBarIconShadow, + WindowColorAsBase, + DarkUserInterface + }; + + Q_ENUM(Color) + Q_ENUM(ImageFile) + Q_ENUM(Gradient) + Q_ENUM(Flag) + + Q_INVOKABLE bool flag(Flag f) const noexcept; + Q_INVOKABLE QColor color(Color role) const noexcept; + QString imageFile(ImageFile imageFile, const QString &fallBack) const noexcept; + QGradientStops gradient(Gradient role) const noexcept; + QPalette palette() const noexcept; + QStringList preferredStyles() const noexcept; + QString defaultTextEditorColorScheme() const noexcept; + + QString id() const noexcept; + QString filePath() const noexcept; + QString displayName() const noexcept; + void setDisplayName(const QString &displayName) noexcept; + + void readSettings(QSettings *const settings) noexcept; + + static bool systemUsesDarkMode() noexcept; + static QPalette initialPalette() noexcept; + +private: + QPair<QColor, QString> readNamedColor(const QString &color) const; + ThemePrivate *d; +}; +} diff --git a/src/UI/Theme/ThemeMac.hh b/src/UI/Theme/ThemeMac.hh new file mode 100644 index 00000000..93d1e0ea --- /dev/null +++ b/src/UI/Theme/ThemeMac.hh @@ -0,0 +1,6 @@ +#pragma once + +namespace Vivy::Utils +{ +void forceMacOSLightAquaApperance(); +} diff --git a/src/UI/Theme/ThemeMac.mm b/src/UI/Theme/ThemeMac.mm new file mode 100644 index 00000000..9b2d3d6f --- /dev/null +++ b/src/UI/Theme/ThemeMac.mm @@ -0,0 +1,21 @@ +#include "ThemeMac.hh" +#include <AppKit/AppKit.h> + +#if !QT_MACOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_14) +@interface NSApplication (MojaveForwardDeclarations) +@property (strong) NSAppearance *appearance NS_AVAILABLE_MAC(10_14); +@end +#endif + +namespace Vivy::Utils { +void forceMacOSLightAquaApperance() +{ +#if __has_builtin(__builtin_available) + if (__builtin_available(macOS 10.14, *)) +#else // Xcode 8 + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion(QOperatingSystemVersion::MacOS, 10, 14, 0)) +#endif + NSApp.appearance = [NSAppearance appearanceNamed:NSAppearanceNameAqua]; +} + +} -- GitLab