Skip to content

Commit

Permalink
Created an option to control wether or not InterSpec will transition …
Browse files Browse the repository at this point in the history
…to the "dark" color theme when the OS does.

Previously there was no indication to the user that they had to create and select a custom color theme in order to prevent InterSpec from applying the OS color scheme.
  • Loading branch information
wcjohns committed Apr 2, 2023
1 parent 95b10b0 commit 3575e77
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 42 deletions.
7 changes: 5 additions & 2 deletions InterSpec_resources/static_text/color_theme_dialog_help.xml
Expand Up @@ -14,7 +14,10 @@ This tool allows you to customize colors on the spectrum and time charts, as wel
icon; you can also upload <em>JSON</em> color themes by using the &quot;<b>Upload...</b>&quot; button at the bottom of the tool. The <em>JSON</em>
representation is convienient if you would like to use the same color theme on multiple devices.
</p>

<p>
When the '<em>Auto apply "Dark" from OS</em>' checkbox is checked, then whenever the operating system transitions into its "dark" color scheme, then <b>InterSpec</b> will automatically apply the default "<em>Dark</em>" color theme; when the operating system goes back to its default or "light" theme, then your selected color theme will be applied, or if you havent selected a color theme, the "Default" color theme will be used.
There is currently no way to customize the auto-applied dark theme.
</p>

<div style="width: 100%">
<img align="left" src="InterSpec_resources/static_text/images/color_theme_dialog_top.png" class="imageBorder" style="width:55%; margin-top: 10px; "/>
Expand All @@ -38,7 +41,7 @@ This tool allows you to customize colors on the spectrum and time charts, as wel


<div style="width: 100%">
<img align="left" src="InterSpec_resources/static_text/images/color_theme_dialog_reflines.svg" class="imageBorder" style="width:55%; margin-top: 10px; "/>
<img align="left" src="InterSpec_resources/static_text/images/color_theme_dialog_reflines.png" class="imageBorder" style="width:55%; margin-top: 10px; "/>

<span style="float:right; width: 44%">
<ul>
Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions data/default_preferences.xml
Expand Up @@ -45,4 +45,5 @@
<pref name="RefLineShowPrev" type="Boolean">true</pref>
<pref name="RefLineShowAssoc" type="Boolean">true</pref>
<pref name="ShowMapDataWarning" type="Boolean">true</pref>
<pref name="AutoDarkFromOs" type="Boolean">true</pref>
</preferences>
41 changes: 28 additions & 13 deletions js/InterSpec.js
Expand Up @@ -395,28 +395,43 @@ function()


//Requires {macOS 10.14, iOS 13.0, iPadOS 13.0, Windows 10} and {Chrome 76, Safari 12.1, Firefox 67}

WT_DECLARE_WT_MEMBER
(SetupOsColorThemeChangeJs, Wt::JavaScriptFunction, "SetupOsColorThemeChangeJs",
(DetectOsColorThemeJs, Wt::JavaScriptFunction, "DetectOsColorThemeJs",
function(id)
{
try
{
var darkQ = window.matchMedia('(prefers-color-scheme: dark)');
var lightQ = window.matchMedia('(prefers-color-scheme: light)');
var noPrefQ = window.matchMedia('(prefers-color-scheme: no-preference)');
var isSupported = darkQ.matches || lightQ.matches || noPrefQ.matches;

if( !isSupported )
throw 'no-support';
const darkQ = window.matchMedia('(prefers-color-scheme: dark)');
const lightQ = window.matchMedia('(prefers-color-scheme: light)');
const noPrefQ = window.matchMedia('(prefers-color-scheme: no-preference)');

if( darkQ.matches )
Wt.emit( id, {name: 'OsColorThemeChange' }, 'dark' );

if( lightQ.matches )
else if( lightQ.matches )
Wt.emit( id, {name: 'OsColorThemeChange' }, 'light' );

if( noPrefQ.matches )
else if( noPrefQ.matches )
Wt.emit( id, {name: 'OsColorThemeChange' }, 'no-preference' );
else
throw 'no-support';
}catch(error)
{
Wt.emit( id, {name: 'OsColorThemeChange' }, 'no-support' );
}
});

WT_DECLARE_WT_MEMBER
(SetupOsColorThemeChangeJs, Wt::JavaScriptFunction, "SetupOsColorThemeChangeJs",
function(id)
{
try
{
const darkQ = window.matchMedia('(prefers-color-scheme: dark)');
const lightQ = window.matchMedia('(prefers-color-scheme: light)');
const noPrefQ = window.matchMedia('(prefers-color-scheme: no-preference)');

if( !darkQ.matches && !lightQ.matches && !noPrefQ.matches )
console.warn( 'No matches for color scheme found.' );

darkQ.addListener( function(e){
if( e && e.matches )
Expand All @@ -435,7 +450,7 @@ function(id)

}catch(error)
{
Wt.emit( id, {name: 'OsColorThemeChange' }, 'no-support' );
console.warn( 'Color theme not supported:', error );
}
}
);
Expand Down
8 changes: 8 additions & 0 deletions src/ColorThemeWindow.cpp
Expand Up @@ -29,6 +29,7 @@
#include <Wt/WText>
#include <Wt/WAnchor>
#include <Wt/WServer>
#include <Wt/WCheckBox>
#include <Wt/WResource>
#include <Wt/WMenuItem>
#include <Wt/WFileUpload>
Expand Down Expand Up @@ -254,6 +255,13 @@ m_apply( nullptr )
WContainerWidget *foot = footer();
AuxWindow::addHelpInFooter( foot, "color-theme-dialog" );

WCheckBox *autoDarkCb = new WCheckBox( "Auto apply \"Dark\" from OS", foot );
autoDarkCb->setFloatSide( Wt::Side::Left );
autoDarkCb->setToolTip( "Apply the \"Dark\" color theme automatically according to"
" the operating systems current value, or when it transisitions." );

InterSpecUser::associateWidget(m_interspec->m_user, "AutoDarkFromOs", autoDarkCb, m_interspec);

m_save = new WPushButton( "Save", foot );
m_apply = new WPushButton( "Apply", foot );
m_save->setHiddenKeepsGeometry( true );
Expand Down
66 changes: 39 additions & 27 deletions src/InterSpec.cpp
Expand Up @@ -3876,45 +3876,41 @@ void InterSpec::osThemeChange( std::string name )
return;
}

//TODO: if( name == "no-support" ), then should hide widgets associated with "AutoDarkFromOs"

try
{
const int colorThemIndex = m_user->preferenceValue<int>("ColorThemeIndex", this);
if( colorThemIndex >= 0 )
return;
const bool autoDark = InterSpecUser::preferenceValue<bool>( "AutoDarkFromOs", this );

const auto oldTheme = ColorTheme::PredefinedColorTheme(-colorThemIndex);

if( oldTheme != ColorTheme::PredefinedColorTheme::DefaultColorTheme )
return;

std::unique_ptr<ColorTheme> theme;

if( name == "dark" )
if( autoDark && (name == "dark") )
{
//Check to see if we already have dark applied
if( m_colorTheme && SpecUtils::icontains( m_colorTheme->theme_name.toUTF8(), "Dark") )
return;

cout << "Will set to dark" << endl;
theme = ColorTheme::predefinedTheme( ColorTheme::PredefinedColorTheme::DarkColorTheme );
}else if( name == "light" || name == "default" || name == "no-preference" || name == "no-support" )
cout << "Will set to dark color theme" << endl;
unique_ptr<ColorTheme> theme = ColorTheme::predefinedTheme( ColorTheme::PredefinedColorTheme::DarkColorTheme );
assert( theme );
if( theme )
applyColorTheme( make_shared<ColorTheme>(*theme) );
}else if( !autoDark || name == "light" || name == "default" || name == "no-preference" || name == "no-support" )
{
//Check to see if we already have light applied
if (m_colorTheme && SpecUtils::icontains(m_colorTheme->theme_name.toUTF8(), "Default"))
if( m_colorTheme
&& (m_colorTheme->dbIndex < 0)
&& (ColorTheme::PredefinedColorTheme(-m_colorTheme->dbIndex) == ColorTheme::PredefinedColorTheme::DarkColorTheme) )
{
cout << "Already have light color theme applied." << endl;
return;
cout << "Will set to default or user specified color theme, from \"Dark\"." << endl;

m_colorTheme = nullptr;
applyColorTheme( nullptr );
}else
{
cout << "Current theme is not \"Dark\", so not setting color theme." << endl;
}

cout << "Will set to default" << endl;
theme = ColorTheme::predefinedTheme( ColorTheme::PredefinedColorTheme::DefaultColorTheme );
}

if( theme )
applyColorTheme( make_shared<ColorTheme>(*theme) );
}catch(...)
}catch( std::exception &e )
{
cerr << "InterSpec::osThemeChange() caught exception - not doing anything" << endl;
cerr << "InterSpec::osThemeChange() caught exception - not doing anything:" << e.what() << endl;
}

cout << "Done applying color theme" << endl;
Expand Down Expand Up @@ -6947,6 +6943,20 @@ void InterSpec::addAboutMenu( Wt::WWidget *parent )
InterSpecUser::associateWidget( m_user, "TabletUseDesktopMenus", checkbox, this );
}//if( is tablet )

WCheckBox *autoDarkCb = new WCheckBox( " Auto apply \"Dark\" theme" );
item = subPopup->addWidget( autoDarkCb );
HelpSystem::attachToolTipOn( item, "Applies the \"Dark\" color theme automatically according to"
" the operating systems current value, or when it transisitions.",
true, HelpSystem::ToolTipPosition::Right );
InterSpecUser::associateWidget( m_user, "AutoDarkFromOs", autoDarkCb, this );

InterSpecUser::addCallbackWhenChanged( m_user, "AutoDarkFromOs", std::bind([](){
InterSpec *viewer = InterSpec::instance();
if( viewer )
viewer->doJavaScript( "try{ Wt.WT.DetectOsColorThemeJs('" + viewer->id() + "'); }"
"catch(e){ console.error('Error with DetectOsColorThemeJs:',e); }" );
}) );

item = subPopup->addMenuItem("Color Themes...");
item->triggered().connect(boost::bind(&InterSpec::showColorThemeWindow, this));

Expand Down Expand Up @@ -8800,12 +8810,14 @@ std::set<int> InterSpec::validForegroundSamples() const
#if( APPLY_OS_COLOR_THEME_FROM_JS && !BUILD_AS_OSX_APP && !IOS && !BUILD_AS_ELECTRON_APP )
void InterSpec::initOsColorThemeChangeDetect()
{
m_osColorThemeChange.reset( new JSignal<std::string>( this, "OsColorThemeChange", true ) );
m_osColorThemeChange.reset( new JSignal<std::string>( this, "OsColorThemeChange", false ) );
m_osColorThemeChange->connect( boost::bind( &InterSpec::osThemeChange, this,
boost::placeholders::_1 ) );

LOAD_JAVASCRIPT(wApp, "js/InterSpec.js", "InterSpec", wtjsDetectOsColorThemeJs);
LOAD_JAVASCRIPT(wApp, "js/InterSpec.js", "InterSpec", wtjsSetupOsColorThemeChangeJs);

doJavaScript( "Wt.WT.DetectOsColorThemeJs('" + id() + "')" );
doJavaScript( "Wt.WT.SetupOsColorThemeChangeJs('" + id() + "')" );
}//void initOsColorThemeChangeDetect()
#endif
Expand Down

0 comments on commit 3575e77

Please sign in to comment.