Implementation for "Light/dark theme should follow system default" (issue SpartanJ/ecode#754).

This commit is contained in:
Martín Lucas Golini
2025-12-22 01:16:05 -03:00
parent 2c70227c09
commit f3b6fcacf4
18 changed files with 467 additions and 41 deletions
+3
View File
@@ -144,6 +144,9 @@ class EE_API Sys {
/** @returns True if the process has any childrens */
static bool processHasChildren( ProcessID pid );
/** @returns True if the operating system is using a dark color scheme */
static bool isOSUsingDarkColorScheme( bool allowUsingCached = true );
};
}} // namespace EE::System
@@ -0,0 +1,34 @@
#pragma once
#include <eepp/config.hpp>
#include <string>
#include <string_view>
#include <type_traits>
namespace EE::UI {
enum class ColorSchemePreference { Light, Dark };
enum class ColorSchemeExtPreference : std::underlying_type_t<ColorSchemePreference> {
Light =
static_cast<std::underlying_type_t<ColorSchemePreference>>( ColorSchemePreference::Light ),
Dark =
static_cast<std::underlying_type_t<ColorSchemePreference>>( ColorSchemePreference::Dark ),
System
};
struct EE_API ColorSchemePreferences {
static ColorSchemePreference fromString( std::string_view str );
static ColorSchemeExtPreference fromStringExt( std::string_view str );
static ColorSchemePreference fromExt( ColorSchemeExtPreference pref );
static ColorSchemeExtPreference toExt( ColorSchemePreference pref );
static std::string toString( ColorSchemePreference pref );
static std::string toString( ColorSchemeExtPreference pref );
};
} // namespace EE::UI
+3 -2
View File
@@ -4,6 +4,7 @@
#include <eepp/scene/scenenode.hpp>
#include <eepp/system/threadpool.hpp>
#include <eepp/system/translator.hpp>
#include <eepp/ui/colorschemepreferences.hpp>
#include <eepp/ui/css/stylesheet.hpp>
#include <eepp/ui/keyboardshortcut.hpp>
@@ -23,8 +24,6 @@ class UIWidget;
class UILayout;
class UIIcon;
enum class ColorSchemePreference { Light, Dark };
class EE_API UISceneNode : public SceneNode {
public:
static UISceneNode* New( EE::Window::Window* window = NULL );
@@ -149,6 +148,8 @@ class EE_API UISceneNode : public SceneNode {
ColorSchemePreference getColorSchemePreference() const;
void setColorSchemePreference( const ColorSchemeExtPreference& colorSchemePreference );
void setColorSchemePreference( const ColorSchemePreference& colorSchemePreference );
const Uint32& getMaxInvalidationDepth() const;
+257
View File
@@ -21,7 +21,9 @@
// This taints the System module!
#if EE_PLATFORM == EE_PLATFORM_ANDROID
#include <android/configuration.h>
#include <eepp/window/engine.hpp>
#include <jni.h>
#endif
#ifdef EE_PLATFORM_POSIX
@@ -41,6 +43,7 @@
#endif
#include <stdlib.h>
#include <windows.h>
#include <winreg.h>
#undef GetDiskFreeSpace
#undef GetTempPath
@@ -105,6 +108,11 @@ typedef DWORD( WINAPI* GetModuleBaseName_t )( HANDLE, HMODULE, LPSTR, DWORD );
using namespace EE::Network;
#endif
#if EE_PLATFORM == EE_PLATFORM_IOS
#include <objc/message.h>
#include <objc/runtime.h>
#endif
#ifndef PATH_MAX
#define PATH_MAX 4096
#endif
@@ -2008,4 +2016,253 @@ bool Sys::processHasChildren( ProcessID pid ) {
return false;
}
static bool _isOSUsingDarkColorScheme() {
#if EE_PLATFORM == EE_PLATFORM_WIN
// Checks the registry for the "AppsUseLightTheme" key.
// 0 = Dark, 1 = Light. If key is missing (Win 7/8), default to Light (false).
HKEY hKey;
const wchar_t* subKey = L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
const wchar_t* valueName = L"AppsUseLightTheme";
if ( RegOpenKeyExW( HKEY_CURRENT_USER, subKey, 0, KEY_READ, &hKey ) != ERROR_SUCCESS ) {
return false;
}
DWORD value = 1; // Default to Light
DWORD size = sizeof( DWORD );
LSTATUS status = RegQueryValueExW( hKey, valueName, nullptr, nullptr,
reinterpret_cast<LPBYTE>( &value ), &size );
RegCloseKey( hKey );
if ( status == ERROR_SUCCESS ) {
return ( value == 0 );
}
return false;
#elif EE_PLATFORM == EE_PLATFORM_IOS
// Logic: [UIScreen.mainScreen.traitCollection userInterfaceStyle] == 2 (Dark)
// 1. Get UIScreen Class
Class uiScreenClass = objc_getClass( "UIScreen" );
if ( !uiScreenClass )
return false; // Should not happen on iOS
// 2. Call [UIScreen mainScreen]
// We must cast objc_msgSend to the correct function signature
typedef id ( *MainScreenMethod )( Class, SEL );
SEL mainScreenSel = sel_registerName( "mainScreen" );
MainScreenMethod getMainScreen = (MainScreenMethod)objc_msgSend;
id mainScreen = getMainScreen( uiScreenClass, mainScreenSel );
if ( !mainScreen )
return false;
// 3. Call [screen traitCollection]
typedef id ( *TraitCollectionMethod )( id, SEL );
SEL traitCollectionSel = sel_registerName( "traitCollection" );
TraitCollectionMethod getTraitCollection = (TraitCollectionMethod)objc_msgSend;
id traits = getTraitCollection( mainScreen, traitCollectionSel );
if ( !traits )
return false;
// 4. Call [traits userInterfaceStyle]
// Return type is NSInteger (long)
typedef long ( *UserInterfaceStyleMethod )( id, SEL );
SEL styleSel = sel_registerName( "userInterfaceStyle" );
UserInterfaceStyleMethod getStyle = (UserInterfaceStyleMethod)objc_msgSend;
long style = getStyle( traits, styleSel );
// 5. Check constants: UIUserInterfaceStyleLight = 1, UIUserInterfaceStyleDark = 2
return ( style == 2 );
#elif EE_PLATFORM == EE_PLATFORM_MACOS
// Checks global user preferences via CoreFoundation (C-API).
// This avoids complex Obj-C Runtime casting and works in CLI apps / before UI init.
// Key: "AppleInterfaceStyle". Value: "Dark" (exists) or null (Light).
bool isDark = false;
CFStringRef key = CFSTR( "AppleInterfaceStyle" );
CFPropertyListRef propertyValue =
CFPreferencesCopyAppValue( key, kCFPreferencesAnyApplication );
if ( propertyValue ) {
if ( CFGetTypeID( propertyValue ) == CFStringGetTypeID() ) {
CFStringRef style = static_cast<CFStringRef>( propertyValue );
// Check if string contains "Dark"
if ( CFStringCompare( style, CFSTR( "Dark" ), 0 ) == kCFCompareEqualTo ) {
isDark = true;
}
}
CFRelease( propertyValue );
}
return isDark;
#elif EE_PLATFORM == EE_PLATFORM_ANDROID
// Logic: ActivityThread.currentApplication().getResources().getConfiguration().uiMode
// 1. Retrieve the environment from your engine
void* rawEnv = Window::Engine::instance()->getPlatformHelper()->getJNIEnv();
if ( !rawEnv )
return false;
// Cast void* to JNIEnv*
JNIEnv* env = static_cast<JNIEnv*>( rawEnv );
bool isDark = false;
// 2. Reflection to get the Application Context without passing it as an argument
// Note: We use the hidden class "android.app.ActivityThread" to get the current app.
jclass activityThreadCls = env->FindClass( "android/app/ActivityThread" );
if ( activityThreadCls ) {
jmethodID currentAppMethod = env->GetStaticMethodID(
activityThreadCls, "currentApplication", "()Landroid/app/Application;" );
if ( currentAppMethod ) {
jobject context = env->CallStaticObjectMethod( activityThreadCls, currentAppMethod );
if ( context ) {
// 3. context.getResources()
jclass contextCls = env->GetObjectClass( context );
jmethodID getResMethod = env->GetMethodID( contextCls, "getResources",
"()Landroid/content/res/Resources;" );
jobject resources = env->CallObjectMethod( context, getResMethod );
if ( resources ) {
// 4. resources.getConfiguration()
jclass resCls = env->GetObjectClass( resources );
jmethodID getConfigMethod = env->GetMethodID(
resCls, "getConfiguration", "()Landroid/content/res/Configuration;" );
jobject config = env->CallObjectMethod( resources, getConfigMethod );
if ( config ) {
// 5. config.uiMode & UI_MODE_NIGHT_MASK
jclass configCls = env->GetObjectClass( config );
jfieldID uiModeField = env->GetFieldID( configCls, "uiMode", "I" );
int uiMode = env->GetIntField( config, uiModeField );
// UI_MODE_NIGHT_MASK (0x30) check against UI_MODE_NIGHT_YES (0x20)
if ( ( uiMode & 0x30 ) == 0x20 ) {
isDark = true;
}
// Cleanup local references to avoid JNI table overflow
env->DeleteLocalRef( config );
env->DeleteLocalRef( configCls );
}
env->DeleteLocalRef( resources );
env->DeleteLocalRef( resCls );
}
env->DeleteLocalRef( context );
env->DeleteLocalRef( contextCls );
}
}
env->DeleteLocalRef( activityThreadCls );
}
// Safety: Clear any exceptions if something wasn't found (e.g. old Android versions)
if ( env->ExceptionCheck() ) {
env->ExceptionClear();
}
return isDark;
#elif EE_PLATFORM == EE_PLATFORM_LINUX || EE_PLATFORM == EE_PLATFORM_BSD
// Helper to parse INI-style files robustly
auto checkFileForDarkTheme = [&]( const std::string& path, const std::string& key ) -> bool {
if ( access( path.c_str(), R_OK ) != 0 )
return false;
std::ifstream file( path );
std::string line;
while ( std::getline( file, line ) ) {
// 1. Trim leading whitespace (handle indented keys)
size_t keyStart = line.find_first_not_of( " \t" );
if ( keyStart == std::string::npos )
continue; // Empty line
// 2. Skip comments
if ( line[keyStart] == '#' || line[keyStart] == ';' )
continue;
// 3. Check if the line starts specifically with our key
if ( line.compare( keyStart, key.length(), key ) == 0 ) {
// 4. Look for '=' after the key
size_t afterKeyIndex = keyStart + key.length();
size_t eqPos = line.find( '=', afterKeyIndex );
if ( eqPos != std::string::npos ) {
// 5. strict check: ensure only whitespace exists between key and '='
// This prevents "Color" matching "ColorScheme" or "gtk-theme" matching
// "gtk-theme-backup"
bool isValidKey = true;
for ( size_t i = afterKeyIndex; i < eqPos; ++i ) {
if ( line[i] != ' ' && line[i] != '\t' ) {
isValidKey = false;
break;
}
}
if ( isValidKey ) {
std::string value = line.substr( eqPos + 1 );
value = String::toLower( value );
if ( value.find( "dark" ) != std::string::npos ) {
return true;
}
}
}
}
}
return false;
};
// 1. Check Environment Variables (GTK_THEME overrides config files)
const char* gtkTheme = std::getenv( "GTK_THEME" );
if ( gtkTheme ) {
std::string theme( gtkTheme );
theme = String::toLower( theme );
if ( theme.find( "dark" ) != std::string::npos )
return true;
}
const char* home = std::getenv( "HOME" );
if ( !home )
return false;
std::string homeStr( home );
// 2. KDE Plasma
if ( checkFileForDarkTheme( homeStr + "/.config/kdeglobals", "ColorScheme" ) ) {
return true;
}
// 3. GTK 3/4 (Gnome, XFCE, Mate, Cinnamon)
if ( checkFileForDarkTheme( homeStr + "/.config/gtk-3.0/settings.ini", "gtk-theme-name" ) ) {
return true;
}
if ( checkFileForDarkTheme( homeStr + "/.config/gtk-4.0/settings.ini", "gtk-theme-name" ) ) {
return true;
}
return false; // Default to light
#elif EE_PLATFORM == EE_PLATFORM_EMSCRIPTEN
// Executes JavaScript: window.matchMedia('(prefers-color-scheme: dark)').matches
return EM_ASM_INT({
if (typeof window !== 'undefined' && window.matchMedia) {
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 1 : 0;
}
return 0;
}) != 0;
#else
return true; // Any other OS default to dark
#endif
}
bool Sys::isOSUsingDarkColorScheme( bool allowUsingCached ) {
static bool isUsingDarkColorScheme = _isOSUsingDarkColorScheme();
if ( allowUsingCached )
return isUsingDarkColorScheme;
isUsingDarkColorScheme = _isOSUsingDarkColorScheme();
return isUsingDarkColorScheme;
}
}} // namespace EE::System
+59
View File
@@ -0,0 +1,59 @@
#include <eepp/system/sys.hpp>
#include <eepp/ui/colorschemepreferences.hpp>
using namespace EE::System;
using namespace std::literals;
namespace EE::UI {
ColorSchemePreference ColorSchemePreferences::fromString( std::string_view str ) {
if ( str == "light"sv )
return ColorSchemePreference::Light;
return ColorSchemePreference::Dark;
}
ColorSchemeExtPreference ColorSchemePreferences::fromStringExt( std::string_view str ) {
if ( str == "system"sv )
return ColorSchemeExtPreference::System;
if ( str == "light"sv )
return ColorSchemeExtPreference::Light;
return ColorSchemeExtPreference::Dark;
}
ColorSchemePreference ColorSchemePreferences::fromExt( ColorSchemeExtPreference pref ) {
switch ( pref ) {
case ColorSchemeExtPreference::Light:
return ColorSchemePreference::Light;
case ColorSchemeExtPreference::Dark:
return ColorSchemePreference::Dark;
case ColorSchemeExtPreference::System:
break;
}
return Sys::isOSUsingDarkColorScheme() ? ColorSchemePreference::Dark
: ColorSchemePreference::Light;
}
ColorSchemeExtPreference ColorSchemePreferences::toExt( ColorSchemePreference pref ) {
if ( pref == ColorSchemePreference::Light )
return ColorSchemeExtPreference::Light;
if ( pref == ColorSchemePreference::Dark )
return ColorSchemeExtPreference::Dark;
return ColorSchemeExtPreference::System;
}
std::string ColorSchemePreferences::toString( ColorSchemePreference pref ) {
if ( pref == ColorSchemePreference::Light )
return "light";
return "dark";
}
std::string ColorSchemePreferences::toString( ColorSchemeExtPreference pref ) {
if ( pref == ColorSchemeExtPreference::Light )
return "light";
if ( pref == ColorSchemeExtPreference::Dark )
return "dark";
return "system";
}
} // namespace EE::UI
+2
View File
@@ -116,6 +116,8 @@ UIIconTheme* IconManager::init( const std::string& iconThemeName, FontTrueType*
{ "pause-fill", 0xEFD7 },
{ "spy-line", 0xF17F },
{ "input-field", 0xF47A },
{ "sun", 0xF1BF },
{ "moon", 0xEF75 },
} ) {
iconTheme->add( UIGlyphIcon::New( icon.first, remixIconFont, icon.second ) );
}
+17
View File
@@ -1078,6 +1078,23 @@ ColorSchemePreference UISceneNode::getColorSchemePreference() const {
return mColorSchemePreference;
}
void UISceneNode::setColorSchemePreference(
const ColorSchemeExtPreference& colorSchemePreference ) {
switch ( colorSchemePreference ) {
case ColorSchemeExtPreference::Light:
setColorSchemePreference( ColorSchemePreference::Light );
break;
case ColorSchemeExtPreference::Dark:
setColorSchemePreference( ColorSchemePreference::Dark );
break;
case ColorSchemeExtPreference::System:
setColorSchemePreference( Sys::isOSUsingDarkColorScheme()
? ColorSchemePreference::Dark
: ColorSchemePreference::Light );
break;
}
}
void UISceneNode::setColorSchemePreference( const ColorSchemePreference& colorSchemePreference ) {
if ( mColorSchemePreference != colorSchemePreference ) {
mColorSchemePreference = colorSchemePreference;
+1
View File
@@ -214,6 +214,7 @@ void UIStyle::applyLightDarkValue( std::string& value ) {
std::string::size_type tokenEnd = 0;
while ( true ) {
// TODO: add support to inner-function calls like: light-dark(rgba(0,0,0,1), rgba(1,1,1,1))
tokenStart = value.find( "light-dark(", tokenStart );
if ( tokenStart != std::string::npos ) {
tokenEnd = String::findCloseBracket( value, tokenStart, '(', ')' );
+3 -6
View File
@@ -136,9 +136,8 @@ void AppConfig::load( const std::string& confPath, std::string& keybindingsPath,
ui.fallbackFont = ini.getValue( "ui", "fallback_font", "fonts/DroidSansFallbackFull.ttf" );
ui.theme = ini.getValue( "ui", "theme" );
ui.language = ini.getValue( "ui", "language" );
ui.colorScheme = ini.getValue( "ui", "ui_color_scheme", "dark" ) == "light"
? ColorSchemePreference::Light
: ColorSchemePreference::Dark;
ui.colorScheme =
ColorSchemePreferences::fromStringExt( ini.getValue( "ui", "ui_color_scheme", "system" ) );
ui.fontHinting =
FontTrueType::fontHintingFromString( ini.getValue( "ui", "font_hinting", "full" ) );
ui.fontAntialiasing = FontTrueType::fontAntialiasingFromString(
@@ -335,9 +334,7 @@ void AppConfig::save( const std::vector<std::string>& recentFiles,
ini.setValue( "ui", "theme", ui.theme );
ini.setValue( "ui", "language", ui.language );
ini.setValue( "ui", "fallback_font", ui.fallbackFont );
ini.setValue(
"ui", "ui_color_scheme",
std::string_view{ ui.colorScheme == ColorSchemePreference::Light ? "light" : "dark" } );
ini.setValue( "ui", "ui_color_scheme", ColorSchemePreferences::toString( ui.colorScheme ) );
ini.setValue( "ui", "font_hinting", FontTrueType::fontHintingToString( ui.fontHinting ) );
ini.setValue( "ui", "font_antialiasing",
FontTrueType::fontAntialiasingToString( ui.fontAntialiasing ) );
+1 -1
View File
@@ -47,7 +47,7 @@ struct UIConfig {
std::string monospaceFont;
std::string terminalFont;
std::string fallbackFont;
ColorSchemePreference colorScheme{ ColorSchemePreference::Dark };
ColorSchemeExtPreference colorScheme{ ColorSchemeExtPreference::Dark };
std::string theme;
std::string language;
FontHinting fontHinting{ FontHinting::Full };
+21 -5
View File
@@ -1203,7 +1203,7 @@ void App::panelPosition( const PanelPosition& panelPosition ) {
mSettings->updateViewMenu();
}
void App::setUIColorScheme( const ColorSchemePreference& colorScheme ) {
void App::setUIColorScheme( const ColorSchemeExtPreference& colorScheme ) {
if ( colorScheme == mUIColorScheme )
return;
mUIColorScheme = mConfig.ui.colorScheme = colorScheme;
@@ -1212,7 +1212,19 @@ void App::setUIColorScheme( const ColorSchemePreference& colorScheme ) {
mPluginManager->setUIThemeReloaded();
}
ColorSchemePreference App::getUIColorScheme() const {
void App::setUIColorSchemeFromUserInteraction( const ColorSchemeExtPreference& colorSchemeExt ) {
setUIColorScheme( colorSchemeExt );
ColorSchemePreference colorScheme = ColorSchemePreferences::fromExt( colorSchemeExt );
if ( colorScheme == ColorSchemePreference::Light &&
mSplitter->getCurrentColorSchemeName() == "eepp" ) {
mSplitter->setColorScheme( "github" );
} else if ( colorScheme == ColorSchemePreference::Dark &&
mSplitter->getCurrentColorSchemeName() == "github" ) {
mSplitter->setColorScheme( "eepp" );
}
}
ColorSchemeExtPreference App::getUIColorScheme() const {
return mUIColorScheme;
}
@@ -4202,8 +4214,11 @@ void App::init( InitParameters& params ) {
mUISceneNode->getTranslator().loadFromFile( langPath );
if ( !params.colorScheme.empty() ) {
mUIColorScheme = params.colorScheme == "light" ? ColorSchemePreference::Light
: ColorSchemePreference::Dark;
mUIColorScheme =
params.colorScheme == "light"
? ColorSchemeExtPreference::Light
: ( params.colorScheme == "dark" ? ColorSchemeExtPreference::Dark
: ColorSchemeExtPreference::System );
}
mUISceneNode->setColorSchemePreference( mUIColorScheme );
@@ -4556,7 +4571,8 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
"Set default application pixel density",
{ 'd', "pixel-density" } );
args::ValueFlag<std::string> prefersColorScheme(
parser, "prefers-color-scheme", "Set the preferred color scheme (\"light\" or \"dark\")",
parser, "prefers-color-scheme",
"Set the preferred color scheme (\"light\", \"dark\" or \"system\")",
{ 'c', "prefers-color-scheme" } );
args::ValueFlag<std::string> css(
parser, "css",
+5 -3
View File
@@ -453,9 +453,11 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
void setFocusEditorOnClose( UIMessageBox* msgBox );
void setUIColorScheme( const ColorSchemePreference& colorScheme );
void setUIColorScheme( const ColorSchemeExtPreference& colorScheme );
ColorSchemePreference getUIColorScheme() const;
void setUIColorSchemeFromUserInteraction( const ColorSchemeExtPreference& colorSchemeExt );
ColorSchemeExtPreference getUIColorScheme() const;
EE::Window::Window* getWindow() const;
@@ -663,7 +665,7 @@ class App : public UICodeEditorSplitter::Client, public PluginContextProvider {
std::unique_ptr<StatusAppOutputController> mStatusAppOutputController;
std::unique_ptr<ProjectBuildManager> mProjectBuildManager;
std::string mLastFileFolder;
ColorSchemePreference mUIColorScheme;
ColorSchemeExtPreference mUIColorScheme;
std::unique_ptr<TerminalManager> mTerminalManager;
std::unique_ptr<PluginManager> mPluginManager;
std::unique_ptr<SettingsMenu> mSettings;
+12 -11
View File
@@ -1267,29 +1267,30 @@ UIMenu* SettingsMenu::createWindowMenu() {
mWindowMenu = UIPopUpMenu::New();
auto shouldCloseCb = []( UIMenuItem* ) -> bool { return false; };
UIPopUpMenu* colorsMenu = UIPopUpMenu::New();
colorsMenu
->addRadioButton( i18n( "system", "System" ),
mApp->getUIColorScheme() == ColorSchemeExtPreference::System )
->setOnShouldCloseCb( shouldCloseCb )
->setTooltipText( i18n(
"prefers_color_scheme_system_tooltip",
"System options will try to pick the system-wide currently preferred color scheme." ) )
->setId( "system" );
colorsMenu
->addRadioButton( i18n( "light", "Light" ),
mApp->getUIColorScheme() == ColorSchemePreference::Light )
mApp->getUIColorScheme() == ColorSchemeExtPreference::Light )
->setOnShouldCloseCb( shouldCloseCb )
->setId( "light" );
colorsMenu
->addRadioButton( i18n( "dark", "Dark" ),
mApp->getUIColorScheme() == ColorSchemePreference::Dark )
mApp->getUIColorScheme() == ColorSchemeExtPreference::Dark )
->setOnShouldCloseCb( shouldCloseCb )
->setId( "dark" );
colorsMenu->on( Event::OnItemClicked, [this]( const Event* event ) {
if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) )
return;
UIMenuItem* item = event->getNode()->asType<UIMenuItem>();
mApp->setUIColorScheme( item->getId() == "light" ? ColorSchemePreference::Light
: ColorSchemePreference::Dark );
if ( item->getId() == "light" && mSplitter->getCurrentColorSchemeName() == "eepp" ) {
mSplitter->setColorScheme( "github" );
} else if ( item->getId() == "dark" &&
mSplitter->getCurrentColorSchemeName() == "github" ) {
mSplitter->setColorScheme( "eepp" );
}
auto colorSchemeExt = ColorSchemePreferences::fromStringExt( item->getId() );
mApp->setUIColorSchemeFromUserInteraction( colorSchemeExt );
} );
mWindowMenu->addSubMenu( i18n( "ui_language", "UI Language" ), findIcon( "globe" ),
createLanguagesMenu() );
@@ -182,6 +182,7 @@ void StatusAppOutputController::createContainer() {
editor->setShowLineNumber( false );
editor->getDocument().reset();
editor->setScrollY( editor->getMaxScroll().y );
editor->setColorScheme( mContext->getSplitter()->getCurrentColorScheme() );
mAppOutput = editor;
mAppOutput->on( Event::OnScrollChange, [this]( auto ) {
mScrollLocked = mAppOutput->getMaxScroll().y == mAppOutput->getScroll().y;
@@ -464,6 +464,7 @@ void StatusBuildOutputController::createContainer() {
editor->getDocument().textInput(
mContext->i18n( "no_build_has_been_run", "No build has been run" ), false );
editor->setScrollY( editor->getMaxScroll().y );
editor->setColorScheme( mContext->getSplitter()->getCurrentColorScheme() );
mButOutput = mContainer->find<UISelectButton>( "but_build_output_output" );
mButIssues = mContainer->find<UISelectButton>( "but_build_output_issues" );
mTableIssues = mContainer->find<UITableView>( "build_output_issues" );
+33 -1
View File
@@ -40,7 +40,7 @@ static const auto LAYOUT = R"xml(
#welcome_ecode #version_number {
cursor: pointer;
font-family: DejaVuSansMono;
text-shadow-color: rgba(0,0,0,0.4);
text-shadow-color: light-dark(#00000019, #00000066);
}
#welcome_ecode #version_number {
font-style: shadow;
@@ -87,6 +87,26 @@ static const auto LAYOUT = R"xml(
#welcome_ecode .right > PushButton:last-of-type {
margin-bottom: 0dp;
}
#welcome_ecode .color_scheme_icon {
lw: 24dp;
lh: 24dp;
background-color: transparent;
border-radius: 12dp;
foreground-position: center;
foreground-tint: var(--font);
transition: all 0.1s;
}
#welcome_ecode .color_scheme_icon:hover {
background-color: var(--primary);
foreground-tint: light-dark(var(--back), var(--font));
cursor: hand;
}
#welcome_ecode #light_color_scheme_but {
foreground-image: icon("sun", 16dp);
}
#welcome_ecode #dark_color_scheme_but {
foreground-image: icon("moon", 16dp);
}
]]>
</style>
<RelativeLayout lw="mp" lh="mp" max-width="512dp" layout_gravity="center">
@@ -125,6 +145,10 @@ static const auto LAYOUT = R"xml(
<tv class="name" id="open_file" text="@string(open_file, Open File)" />
<tv class="shortcut" id="open_file_shortcut" text="Ctrl + O" />
</hbox>
<hbox layout-gravity="center">
<Widget id="light_color_scheme_but" class="color_scheme_icon" />
<Widget id="dark_color_scheme_but" class="color_scheme_icon" />
</hbox>
</vbox>
</vbox>
<vbox class="right" lw="0" lh="wc" lw8="0.5" lg="center">
@@ -254,6 +278,14 @@ UIWelcomeScreen::UIWelcomeScreen( App* app ) :
find<UITextView>( "open_file_shortcut" )->setText( mApp->getKeybind( "open-file" ) );
find( "light_color_scheme_but" )->onClick( [this]( auto ) {
mApp->setUIColorSchemeFromUserInteraction( ColorSchemeExtPreference::Light );
} );
find( "dark_color_scheme_but" )->onClick( [this]( auto ) {
mApp->setUIColorSchemeFromUserInteraction( ColorSchemeExtPreference::Dark );
} );
auto welcomeDisabledChk = find<UICheckBox>( "disable_welcome_screen" );
welcomeDisabledChk->on( Event::OnValueChange, [welcomeDisabledChk, this]( auto ) {
mApp->getConfig().ui.welcomeScreen = !welcomeDisabledChk->isChecked();
+13 -11
View File
@@ -435,10 +435,8 @@ void App::refreshStyleSheet() {
setUserDefaultTheme();
}
if ( !mCurrentLayout.empty() && FileSystem::fileExists( mCurrentLayout ) &&
mUIContainer != NULL ) {
loadLayout( mCurrentLayout );
}
mInvalidationLayout = InvalidationType::Memory;
reloadLayout();
mUpdateStyleSheet = false;
mUpdateBaseStyleSheet = false;
@@ -1157,17 +1155,21 @@ void App::createAppMenu() {
UIPopUpMenu* colorsMenu = UIPopUpMenu::New();
colorsMenu
->addRadioButton( i18n( "light", "Light" ), mUIColorScheme == ColorSchemePreference::Light )
->addRadioButton( i18n( "system", "System" ),
mUIColorScheme == ColorSchemeExtPreference::System )
->setId( "system" );
colorsMenu
->addRadioButton( i18n( "light", "Light" ),
mUIColorScheme == ColorSchemeExtPreference::Light )
->setId( "light" );
colorsMenu
->addRadioButton( i18n( "dark", "Dark" ), mUIColorScheme == ColorSchemePreference::Dark )
->addRadioButton( i18n( "dark", "Dark" ), mUIColorScheme == ColorSchemeExtPreference::Dark )
->setId( "dark" );
colorsMenu->on( Event::OnItemClicked, [this]( const Event* event ) {
if ( !event->getNode()->isType( UI_TYPE_MENUITEM ) )
return;
UIMenuItem* item = event->getNode()->asType<UIMenuItem>();
mUIColorScheme =
item->getId() == "light" ? ColorSchemePreference::Light : ColorSchemePreference::Dark;
mUIColorScheme = ColorSchemePreferences::fromStringExt( item->getId() );
mUISceneNode->setColorSchemePreference( mUIColorScheme );
updateLayoutFunc( InvalidationType::Memory );
} );
@@ -1289,8 +1291,7 @@ void App::init( const Float& pixelDensityConf, const bool& useAppTheme, const st
mAppUISceneNode->enableDrawInvalidation();
mUISceneNode->enableDrawInvalidation();
mUIColorScheme =
colorScheme == "light" ? ColorSchemePreference::Light : ColorSchemePreference::Dark;
mUIColorScheme = ColorSchemePreferences::fromStringExt( colorScheme );
mUISceneNode->setColorSchemePreference( mUIColorScheme );
FontTrueType* remixIconFont = loadFont( "icon", "fonts/remixicon.ttf" );
@@ -1544,7 +1545,8 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) {
"Use the default application theme in the editor.",
{ 'u', "use-app-theme" } );
args::ValueFlag<std::string> prefersColorScheme(
parser, "prefers-color-scheme", "Set the preferred color scheme (\"light\" or \"dark\")",
parser, "prefers-color-scheme",
"Set the preferred color scheme (\"light\", \"dark\" or \"system\")",
{ 'c', "prefers-color-scheme" } );
try {
+1 -1
View File
@@ -205,7 +205,7 @@ class App : public UICodeEditorSplitter::Client {
UILayout* mPreviewLayout{ nullptr };
UIWidget* mSidePanel{ nullptr };
std::unordered_set<Doc::TextDocument*> mTmpDocs;
ColorSchemePreference mUIColorScheme;
ColorSchemeExtPreference mUIColorScheme;
Drawable* findIcon( const std::string& icon );
};