Fix Dark Mode issues on Linux(via LAB) (#5044)

* GUI_App.cpp: trailing whitespace cleanup

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>

* StateColor.hpp: trailing whitespace cleanup

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>

* implementing LAB color routines

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>

* Fixes 3667: light/dark fixes for Unsaved Changes dialog

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>

* Fixes: 3675 - set dark mode colors for tabs

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>

* GUI_App: use LAB for fallback and sanity checks

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>

---------

Signed-off-by: Jamin W. Collins <jamin.collins@gmail.com>
Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
Jamin Collins 2024-04-23 06:46:55 -07:00 committed by GitHub
parent d163cea8f8
commit 315eee3493
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 166 additions and 15 deletions

View file

@ -959,7 +959,7 @@ void GUI_App::post_init()
if (app_config->get("stealth_mode") == "false") if (app_config->get("stealth_mode") == "false")
hms_query = new HMSQuery(); hms_query = new HMSQuery();
m_show_gcode_window = app_config->get_bool("show_gcode_window"); m_show_gcode_window = app_config->get_bool("show_gcode_window");
if (m_networking_need_update) { if (m_networking_need_update) {
//updating networking //updating networking
@ -2807,7 +2807,7 @@ void GUI_App::init_label_colours()
m_color_label_modified = is_dark_mode ? wxColour("#F1754E") : wxColour("#F1754E"); m_color_label_modified = is_dark_mode ? wxColour("#F1754E") : wxColour("#F1754E");
m_color_label_sys = is_dark_mode ? wxColour("#B2B3B5") : wxColour("#363636"); m_color_label_sys = is_dark_mode ? wxColour("#B2B3B5") : wxColour("#363636");
#ifdef _WIN32 #if defined(_WIN32) || defined(__linux__) || defined(__APPLE__)
m_color_label_default = is_dark_mode ? wxColour(250, 250, 250) : m_color_label_sys; // wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT); m_color_label_default = is_dark_mode ? wxColour(250, 250, 250) : m_color_label_sys; // wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
m_color_highlight_label_default = is_dark_mode ? wxColour(230, 230, 230): wxSystemSettings::GetColour(/*wxSYS_COLOUR_HIGHLIGHTTEXT*/wxSYS_COLOUR_WINDOWTEXT); m_color_highlight_label_default = is_dark_mode ? wxColour(230, 230, 230): wxSystemSettings::GetColour(/*wxSYS_COLOUR_HIGHLIGHTTEXT*/wxSYS_COLOUR_WINDOWTEXT);
m_color_highlight_default = is_dark_mode ? wxColour(78, 78, 78) : wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT); m_color_highlight_default = is_dark_mode ? wxColour(78, 78, 78) : wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT);
@ -2920,22 +2920,38 @@ void GUI_App::UpdateDarkUI(wxWindow* window, bool highlited/* = false*/, bool ju
/*if (m_is_dark_mode != dark_mode() ) /*if (m_is_dark_mode != dark_mode() )
m_is_dark_mode = dark_mode();*/ m_is_dark_mode = dark_mode();*/
if (m_is_dark_mode) { if (m_is_dark_mode) {
auto original_col = window->GetBackgroundColour();
auto bg_col = StateColor::darkModeColorFor(original_col);
if (bg_col != original_col) { auto orig_col = window->GetBackgroundColour();
auto bg_col = StateColor::darkModeColorFor(orig_col);
// there are cases where the background color of an item is bright, specifically:
// * the background color of a button: #009688 -- 73
if (bg_col != orig_col) {
window->SetBackgroundColour(bg_col); window->SetBackgroundColour(bg_col);
} }
original_col = window->GetForegroundColour(); orig_col = window->GetForegroundColour();
auto fg_col = StateColor::darkModeColorFor(original_col); auto fg_col = StateColor::darkModeColorFor(orig_col);
auto fg_l = StateColor::GetLightness(fg_col);
if (fg_col != original_col) { auto color_difference = StateColor::GetColorDifference(bg_col, fg_col);
window->SetForegroundColour(fg_col);
// fallback and sanity check with LAB
// color difference of less than 2 or 3 is not normally visible, and even less than 30-40 doesn't stand out
if (color_difference < 10) {
fg_col = StateColor::SetLightness(fg_col, 90);
} }
// some of the stock colors have a lightness of ~49
if (fg_l < 45) {
fg_col = StateColor::SetLightness(fg_col, 70);
}
// at this point it shouldn't be possible that fg_col is the same as bg_col, but let's be safe
if (fg_col == bg_col) {
fg_col = StateColor::SetLightness(fg_col, 70);
}
window->SetForegroundColour(fg_col);
} }
else { else {
auto original_col = window->GetBackgroundColour(); auto original_col = window->GetBackgroundColour();
@ -3891,7 +3907,7 @@ void GUI_App::on_http_error(wxCommandEvent &evt)
MessageDialog msg_dlg(nullptr, _L("The version of Orca Slicer is too low and needs to be updated to the latest version before it can be used normally"), "", wxAPPLY | wxOK); MessageDialog msg_dlg(nullptr, _L("The version of Orca Slicer is too low and needs to be updated to the latest version before it can be used normally"), "", wxAPPLY | wxOK);
if (msg_dlg.ShowModal() == wxOK) { if (msg_dlg.ShowModal() == wxOK) {
} }
} }
// request login // request login

View file

@ -1533,7 +1533,6 @@ void UnsavedChangesDialog::update_list()
text_left->SetFont(::Label::Head_13); text_left->SetFont(::Label::Head_13);
text_left->Wrap(-1); text_left->Wrap(-1);
text_left->SetForegroundColour(GREY700); text_left->SetForegroundColour(GREY700);
text_left->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
sizer_left_v->Add(text_left, 0, wxLEFT, 37); sizer_left_v->Add(text_left, 0, wxLEFT, 37);
@ -1562,7 +1561,6 @@ void UnsavedChangesDialog::update_list()
text_left->SetFont(::Label::Body_13); text_left->SetFont(::Label::Body_13);
text_left->Wrap(-1); text_left->Wrap(-1);
text_left->SetForegroundColour(GREY700); text_left->SetForegroundColour(GREY700);
text_left->SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
sizer_left_v->Add(text_left, 0, wxLEFT, 51 ); sizer_left_v->Add(text_left, 0, wxLEFT, 51 );

View file

@ -1,4 +1,5 @@
#include "StateColor.hpp" #include "StateColor.hpp"
#include <cmath>
static bool gDarkMode = false; static bool gDarkMode = false;
@ -41,7 +42,136 @@ static std::map<wxColour, wxColour> gDarkColors{
//{"#F0F0F0", "#4C4C54"}, //{"#F0F0F0", "#4C4C54"},
}; };
std::map<wxColour, wxColour> const & StateColor::GetDarkMap() std::tuple<double, double, double> StateColor::GetLAB(const wxColour& color) {
// Convert color to RGB color space
double r = color.Red() / 255.0;
double g = color.Green() / 255.0;
double b = color.Blue() / 255.0;
// Convert to XYZ color space
double x = 0.412453*r + 0.357580*g + 0.180423*b;
double y = 0.212671*r + 0.715160*g + 0.072169*b;
double z = 0.019334*r + 0.119193*g + 0.950227*b;
// Normalize XYZ values
double x_n = x / 0.950456;
double y_n = y / 1.0;
double z_n = z / 1.088754;
// Convert to LAB color space
double epsilon = 0.008856;
double kappa = 903.3;
double fx = (x_n > epsilon) ? cbrt(x_n) : (kappa*x_n + 16.0) / 116.0;
double fy = (y_n > epsilon) ? cbrt(y_n) : (kappa*y_n + 16.0) / 116.0;
double fz = (z_n > epsilon) ? cbrt(z_n) : (kappa*z_n + 16.0) / 116.0;
double l = 116.0 * fy - 16.0;
double a = 500.0 * (fx - fy);
double b_lab = 200.0 * (fy - fz);
return std::tuple<double, double, double>(l, a, b_lab);
}
double StateColor::LAB_Delta_E(const wxColour& color1, const wxColour& color2) {
auto [l1, a1, b1] = GetLAB(color1);
auto [l2, a2, b2] = GetLAB(color2);
return sqrt((l1 - l2) * (l1 - l2) + (a1 - a2) * (a1 - a2) + (b1 - b2) * (b1 - b2));
}
double StateColor::GetColorDifference(const wxColour& color1, const wxColour& color2) {
return LAB_Delta_E(color1, color2);
}
double StateColor::GetLightness(const wxColour& color) {
auto [l, a, b_lab] = GetLAB(color);
return l;
}
// Function to lighten or darken a wxColour using LAB color space
wxColour StateColor::SetLightness(const wxColour& color, double lightness) {
auto [l, a, b_lab] = GetLAB(color);
// Clamp lightness value
l = std::max(0.0, std::min(100.0, lightness));
// Convert back to XYZ color space
double fy_3 = (l + 16.0) / 116.0;
double fx_3 = a / 500.0 + fy_3;
double fz_3 = fy_3 - b_lab / 200.0;
double epsilon = 0.008856;
double kappa = 903.3;
double x_3 = (fx_3 > epsilon) ? fx_3 * fx_3 * fx_3 : (116.0 * fx_3 - 16.0) / kappa;
double y_3 = (l > kappa*epsilon) ? fy_3 * fy_3 * fy_3 : l / kappa;
double z_3 = (fz_3 > epsilon) ? fz_3 * fz_3 * fz_3 : (116.0 * fz_3 - 16.0) / kappa;
// Denormalize XYZ values
double x = x_3 * 0.950456;
double y = y_3 * 1.0;
double z = z_3 * 1.088754;
// Convert XYZ to RGB
double r_new = 3.240479*x - 1.537150*y - 0.498535*z;
double g_new = -0.969256*x + 1.875992*y + 0.041556*z;
double b_new = 0.055648*x - 0.204043*y + 1.057311*z;
// Clamp RGB values
r_new = std::max(0.0, std::min(1.0, r_new));
g_new = std::max(0.0, std::min(1.0, g_new));
b_new = std::max(0.0, std::min(1.0, b_new));
// Convert back to wxColour
int r_int = static_cast<int>(r_new * 255);
int g_int = static_cast<int>(g_new * 255);
int b_int = static_cast<int>(b_new * 255);
return wxColour(r_int, g_int, b_int);
}
wxColour StateColor::LightenDarkenColor(const wxColour& color, int amount) {
auto [l, a, b_lab] = GetLAB(color);
// Modify lightness
l += amount;
// Clamp lightness value
l = std::max(0.0, std::min(100.0, l));
// Convert back to XYZ color space
double fy_3 = (l + 16.0) / 116.0;
double fx_3 = a / 500.0 + fy_3;
double fz_3 = fy_3 - b_lab / 200.0;
double epsilon = 0.008856;
double kappa = 903.3;
double x_3 = (fx_3 > epsilon) ? fx_3 * fx_3 * fx_3 : (116.0 * fx_3 - 16.0) / kappa;
double y_3 = (l > kappa*epsilon) ? fy_3 * fy_3 * fy_3 : l / kappa;
double z_3 = (fz_3 > epsilon) ? fz_3 * fz_3 * fz_3 : (116.0 * fz_3 - 16.0) / kappa;
// Denormalize XYZ values
double x = x_3 * 0.950456;
double y = y_3 * 1.0;
double z = z_3 * 1.088754;
// Convert XYZ to RGB
double r_new = 3.240479*x - 1.537150*y - 0.498535*z;
double g_new = -0.969256*x + 1.875992*y + 0.041556*z;
double b_new = 0.055648*x - 0.204043*y + 1.057311*z;
// Clamp RGB values
r_new = std::max(0.0, std::min(1.0, r_new));
g_new = std::max(0.0, std::min(1.0, g_new));
b_new = std::max(0.0, std::min(1.0, b_new));
// Convert back to wxColour
int r_int = static_cast<int>(r_new * 255);
int g_int = static_cast<int>(g_new * 255);
int b_int = static_cast<int>(b_new * 255);
return wxColour(r_int, g_int, b_int);
}
std::map<wxColour, wxColour> const & StateColor::GetDarkMap()
{ {
return gDarkColors; return gDarkColors;
} }

View file

@ -9,7 +9,7 @@ class StateColor
{ {
public: public:
enum State { enum State {
Normal = 0, Normal = 0,
Enabled = 1, Enabled = 1,
Checked = 2, Checked = 2,
Focused = 4, Focused = 4,
@ -23,6 +23,13 @@ public:
}; };
public: public:
static std::tuple<double, double, double> GetLAB(const wxColour& color);
static double GetLightness(const wxColour& color);
static wxColour SetLightness(const wxColour& color, double lightness);
static wxColour LightenDarkenColor(const wxColour& color, int amount);
static double GetColorDifference(const wxColour& c1, const wxColour& c2);
static double LAB_Delta_E(const wxColour& c1, const wxColour& c2);
static void SetDarkMode(bool dark); static void SetDarkMode(bool dark);
static std::map<wxColour, wxColour> const & GetDarkMap(); static std::map<wxColour, wxColour> const & GetDarkMap();