Skip to content

Commit

Permalink
Merge pull request #7862 from cbjeukendrup/platform-theme-2.0
Browse files Browse the repository at this point in the history
Update PlatformTheme: now also detects System High Contrast
  • Loading branch information
RomanPudashkin committed Apr 2, 2021
2 parents ebcb40f + 9060be6 commit 6fe71f9
Show file tree
Hide file tree
Showing 13 changed files with 223 additions and 135 deletions.
26 changes: 22 additions & 4 deletions src/appshell/qml/Preferences/internal/ThemeSample.qml
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import QtQuick 2.15
import MuseScore.UiComponents 1.0

Rectangle {
id: root
Expand All @@ -10,16 +11,15 @@ Rectangle {
property color buttonColor
property color accentColor

signal clicked

width: 112
height: 84

radius: 4
color: backgroundPrimaryColor

border.color: strokeColor
border.width: 1

Rectangle {
RoundedRectangle {
anchors.fill: parent
anchors.topMargin: 12
anchors.leftMargin: 16
Expand All @@ -29,6 +29,8 @@ Rectangle {
border.color: root.strokeColor
border.width: 1

bottomRightRadius: borderRect.radius

Column {
anchors.fill: parent
anchors.topMargin: 6
Expand Down Expand Up @@ -104,4 +106,20 @@ Rectangle {
}
}
}

Rectangle {
id: borderRect
anchors.fill: parent
color: "transparent"
radius: 4
border.width: 1
border.color: mouseArea.containsMouse ? root.accentColor : root.strokeColor
}

MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: root.clicked()
}
}
17 changes: 2 additions & 15 deletions src/appshell/qml/Preferences/internal/ThemesSection.qml
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,8 @@ Column {
buttonColor: modelData.buttonColor
accentColor: modelData.accentColor

MouseArea {
anchors.fill: parent
hoverEnabled: true

onClicked: {
root.themeChangeRequested(model.index)
}

onEntered: {
parent.border.color = modelData.accentColor
}

onExited: {
parent.border.color = modelData.backgroundPrimaryColor
}
onClicked: {
root.themeChangeRequested(model.index)
}
}

Expand Down
14 changes: 6 additions & 8 deletions src/framework/ui/internal/iplatformtheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,9 @@

#include "modularity/imoduleexport.h"
#include "async/channel.h"
#include "uitypes.h"

#include <QWidget>
class QWidget;

namespace mu::ui {
class IPlatformTheme : MODULE_EXPORT_INTERFACE
Expand All @@ -38,14 +39,11 @@ class IPlatformTheme : MODULE_EXPORT_INTERFACE

virtual bool isFollowSystemThemeAvailable() const = 0;

virtual bool isDarkMode() const = 0;
virtual async::Channel<bool> darkModeSwitched() const = 0;
virtual ThemeCode themeCode() const = 0;
virtual async::Channel<ThemeCode> themeCodeChanged() const = 0;

/// Performs platform-specific styling of the application.
virtual void setAppThemeDark(bool isDark) = 0;

/// Performs platform-specific styling of the window.
virtual void applyPlatformStyle(QWidget* window) = 0;
virtual void applyPlatformStyleOnAppForTheme(ThemeCode themeCode) = 0;
virtual void applyPlatformStyleOnWindowForTheme(QWidget* window, ThemeCode themeCode) = 0;
};
}

Expand Down
13 changes: 8 additions & 5 deletions src/framework/ui/internal/platform/macos/macosplatformtheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,17 @@ class MacOSPlatformTheme : public IPlatformTheme

bool isFollowSystemThemeAvailable() const override;

bool isDarkMode() const override;
async::Channel<bool> darkModeSwitched() const override;
ThemeCode themeCode() const override;
async::Channel<ThemeCode> themeCodeChanged() const override;

void setAppThemeDark(bool) override;
void applyPlatformStyle(QWidget*) override;
void applyPlatformStyleOnAppForTheme(ThemeCode themeCode) override;
void applyPlatformStyleOnWindowForTheme(QWidget* window, ThemeCode themeCode) override;

private:
async::Channel<bool> m_darkModeSwitched;
bool isSystemDarkMode() const;
bool isSystemHighContrast() const;

async::Channel<ThemeCode> m_channel;
};
}

Expand Down
80 changes: 65 additions & 15 deletions src/framework/ui/internal/platform/macos/macosplatformtheme.mm
Original file line number Diff line number Diff line change
Expand Up @@ -18,51 +18,101 @@
//=============================================================================

#include "macosplatformtheme.h"
#include "log.h"

#include <Cocoa/Cocoa.h>
#include <QWidget>

using namespace mu::ui;
using namespace mu::async;

id<NSObject> darkModeObserverToken;
id<NSObject> darkModeObserverToken = nil;
id<NSObject> contrastObserverToken = nil;

void MacOSPlatformTheme::startListening()
{
NSDistributedNotificationCenter* n = [NSDistributedNotificationCenter defaultCenter];
darkModeObserverToken = [n addObserverForName:@"AppleInterfaceThemeChangedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification*) { m_darkModeSwitched.send(isDarkMode()); }];
if (!darkModeObserverToken) {
darkModeObserverToken = [[NSDistributedNotificationCenter defaultCenter]
addObserverForName:@"AppleInterfaceThemeChangedNotification"
object:nil
queue:nil
usingBlock:^(NSNotification*) {
m_channel.send(themeCode());
}];
}

if (!contrastObserverToken) {
contrastObserverToken = [[[NSWorkspace sharedWorkspace] notificationCenter]
addObserverForName:NSWorkspaceAccessibilityDisplayOptionsDidChangeNotification
object:nil
queue:nil
usingBlock:^(NSNotification*) {
m_channel.send(themeCode());
}];
}
}

void MacOSPlatformTheme::stopListening()
{
NSDistributedNotificationCenter* n = [NSDistributedNotificationCenter defaultCenter];
[n removeObserver:darkModeObserverToken];
if (darkModeObserverToken) {
[[NSDistributedNotificationCenter defaultCenter] removeObserver:darkModeObserverToken];
darkModeObserverToken = nil;
}

if (contrastObserverToken) {
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:contrastObserverToken];
contrastObserverToken = nil;
}
}

bool MacOSPlatformTheme::isFollowSystemThemeAvailable() const
{
// Supported from macOS 10.14, which is our minimum supported version
return true;
}

bool MacOSPlatformTheme::isDarkMode() const
ThemeCode MacOSPlatformTheme::themeCode() const
{
if (isSystemDarkMode()) {
if (isSystemHighContrast()) {
return HIGH_CONTRAST_THEME_CODE;
}
return DARK_THEME_CODE;
}
//! NOTE When system is in light mode, don't automatically use
//! high contrast theme, because it is too dark.
//! Light high contrast theme would be nice.
return LIGHT_THEME_CODE;
}

Channel<ThemeCode> MacOSPlatformTheme::themeCodeChanged() const
{
return m_channel;
}

bool MacOSPlatformTheme::isSystemDarkMode() const
{
NSString* systemMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
return ([systemMode isEqualToString:@"Dark"]);
return [systemMode isEqualToString:@"Dark"];
}

Channel<bool> MacOSPlatformTheme::darkModeSwitched() const
bool MacOSPlatformTheme::isSystemHighContrast() const
{
return m_darkModeSwitched;
return [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldIncreaseContrast];
}

void MacOSPlatformTheme::setAppThemeDark(bool dark)
void MacOSPlatformTheme::applyPlatformStyleOnAppForTheme(ThemeCode themeCode)
{
[NSApp setAppearance:[NSAppearance appearanceNamed:dark ? NSAppearanceNameDarkAqua : NSAppearanceNameAqua]];
// The system will turn these appearance names into their high contrast
// counterparts automatically if system high contrast is enabled
if (themeCode == LIGHT_THEME_CODE) {
[NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameAqua]];
} else {
[NSApp setAppearance:[NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]];
}
}

void MacOSPlatformTheme::applyPlatformStyle(QWidget* widget)
void MacOSPlatformTheme::applyPlatformStyleOnWindowForTheme(QWidget* widget, ThemeCode)
{
QColor backgroundColor = widget->palette().window().color();
NSView* nsView = (__bridge NSView*)reinterpret_cast<void*>(widget->winId());
Expand Down
12 changes: 6 additions & 6 deletions src/framework/ui/internal/platform/stub/stubplatformtheme.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,20 @@ bool StubPlatformTheme::isFollowSystemThemeAvailable() const
return false;
}

bool StubPlatformTheme::isDarkMode() const
ThemeCode StubPlatformTheme::themeCode() const
{
return false;
return LIGHT_THEME_CODE;
}

Channel<bool> StubPlatformTheme::darkModeSwitched() const
Channel<ThemeCode> StubPlatformTheme::themeCodeChanged() const
{
return m_darkModeSwitched;
return m_channel;
}

void StubPlatformTheme::setAppThemeDark(bool)
void StubPlatformTheme::applyPlatformStyleOnAppForTheme(ThemeCode)
{
}

void StubPlatformTheme::applyPlatformStyle(QWidget*)
void StubPlatformTheme::applyPlatformStyleOnWindowForTheme(QWidget*, ThemeCode)
{
}
10 changes: 5 additions & 5 deletions src/framework/ui/internal/platform/stub/stubplatformtheme.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,14 @@ class StubPlatformTheme : public IPlatformTheme

bool isFollowSystemThemeAvailable() const override;

bool isDarkMode() const override;
async::Channel<bool> darkModeSwitched() const override;
ThemeCode themeCode() const override;
async::Channel<ThemeCode> themeCodeChanged() const override;

void setAppThemeDark(bool) override;
void applyPlatformStyle(QWidget*) override;
void applyPlatformStyleOnAppForTheme(ThemeCode themeCode) override;
void applyPlatformStyleOnWindowForTheme(QWidget* window, ThemeCode themeCode) override;

private:
async::Channel<bool> m_darkModeSwitched;
async::Channel<ThemeCode> m_channel;
};
}

Expand Down
Loading

0 comments on commit 6fe71f9

Please sign in to comment.