Skip to content

Commit

Permalink
Fix various Dark/Light Theme inconsistencies
Browse files Browse the repository at this point in the history
  • Loading branch information
bhennion committed Mar 23, 2024
1 parent 33fee4c commit 6166a29
Show file tree
Hide file tree
Showing 10 changed files with 211 additions and 85 deletions.
33 changes: 0 additions & 33 deletions src/core/control/XournalMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -457,39 +457,6 @@ void on_startup(GApplication* application, XMPtr app_data) {

app_data->control = std::make_unique<Control>(application, app_data->gladePath.get(), app_data->disableAudio);

// Set up icons
{
const auto uiPath = app_data->gladePath->getFirstSearchPath();
const auto lightColorIcons = (uiPath / "iconsColor-light").u8string();
const auto darkColorIcons = (uiPath / "iconsColor-dark").u8string();
const auto lightLucideIcons = (uiPath / "iconsLucide-light").u8string();
const auto darkLucideIcons = (uiPath / "iconsLucide-dark").u8string();

// icon load order from lowest priority to highest priority
std::vector<std::string> iconLoadOrder = {};
const auto chosenTheme = app_data->control->getSettings()->getIconTheme();
switch (chosenTheme) {
case ICON_THEME_COLOR:
iconLoadOrder = {darkLucideIcons, lightLucideIcons, darkColorIcons, lightColorIcons};
break;
case ICON_THEME_LUCIDE:
iconLoadOrder = {darkColorIcons, lightColorIcons, darkLucideIcons, lightLucideIcons};
break;
default:
g_message("Unknown icon theme!");
}
const auto darkTheme = app_data->control->getSettings()->isDarkTheme();
if (darkTheme) {
for (size_t i = 0; 2 * i + 1 < iconLoadOrder.size(); ++i) {
std::swap(iconLoadOrder[2 * i], iconLoadOrder[2 * i + 1]);
}
}

for (auto& p: iconLoadOrder) {
gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), p.c_str());
}
}

auto& globalLatexTemplatePath = app_data->control->getSettings()->latexSettings.globalTemplatePath;
if (globalLatexTemplatePath.empty()) {
globalLatexTemplatePath = findResourcePath("resources/") / "default_template.tex";
Expand Down
30 changes: 16 additions & 14 deletions src/core/control/settings/Settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,12 +107,12 @@ void Settings::loadDefault() {
this->stylusCursorType = STYLUS_CURSOR_DOT;
this->eraserVisibility = ERASER_VISIBILITY_ALWAYS;
this->iconTheme = ICON_THEME_COLOR;
this->themeVariant = THEME_VARIANT_USE_SYSTEM;
this->highlightPosition = false;
this->cursorHighlightColor = 0x80FFFF00; // Yellow with 50% opacity
this->cursorHighlightRadius = 30.0;
this->cursorHighlightBorderColor = 0x800000FF; // Blue with 50% opacity
this->cursorHighlightBorderWidth = 0.0;
this->darkTheme = false;
this->useStockIcons = false;
this->scrollbarHideType = SCROLLBAR_HIDE_NONE;
this->disableScrollbarFadeout = false;
Expand Down Expand Up @@ -450,6 +450,8 @@ void Settings::parseItem(xmlDocPtr doc, xmlNodePtr cur) {
this->eraserVisibility = eraserVisibilityFromString(reinterpret_cast<const char*>(value));
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("iconTheme")) == 0) {
this->iconTheme = iconThemeFromString(reinterpret_cast<const char*>(value));
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("themeVariant")) == 0) {
this->themeVariant = themeVariantFromString(reinterpret_cast<const char*>(value));
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("highlightPosition")) == 0) {
this->highlightPosition = xmlStrcmp(value, reinterpret_cast<const xmlChar*>("true")) == 0;
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("cursorHighlightColor")) == 0) {
Expand All @@ -460,8 +462,6 @@ void Settings::parseItem(xmlDocPtr doc, xmlNodePtr cur) {
this->cursorHighlightBorderColor = g_ascii_strtoull(reinterpret_cast<const char*>(value), nullptr, 10);
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("cursorHighlightBorderWidth")) == 0) {
this->cursorHighlightBorderWidth = g_ascii_strtod(reinterpret_cast<const char*>(value), nullptr);
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("darkTheme")) == 0) {
this->darkTheme = xmlStrcmp(value, reinterpret_cast<const xmlChar*>("true")) == 0;
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("useStockIcons")) == 0) {
this->useStockIcons = xmlStrcmp(value, reinterpret_cast<const xmlChar*>("true")) == 0;
} else if (xmlStrcmp(name, reinterpret_cast<const xmlChar*>("defaultSaveName")) == 0) {
Expand Down Expand Up @@ -972,12 +972,14 @@ void Settings::save() {
xmlNode = saveProperty("iconTheme", iconThemeToString(this->iconTheme), root);
ATTACH_COMMENT("The icon theme, allowed values are \"iconsColor\", \"iconsLucide\"");

xmlNode = saveProperty("themeVariant", themeVariantToString(this->themeVariant), root);
ATTACH_COMMENT("Dark/light mode, allowed values are \"useSystem\", \"forceLight\", \"forceDark\"");

SAVE_BOOL_PROP(highlightPosition);
xmlNode = savePropertyUnsigned("cursorHighlightColor", uint32_t(cursorHighlightColor), root);
xmlNode = savePropertyUnsigned("cursorHighlightBorderColor", uint32_t(cursorHighlightBorderColor), root);
SAVE_DOUBLE_PROP(cursorHighlightRadius);
SAVE_DOUBLE_PROP(cursorHighlightBorderWidth);
SAVE_BOOL_PROP(darkTheme);
SAVE_BOOL_PROP(useStockIcons);

SAVE_BOOL_PROP(disableScrollbarFadeout);
Expand Down Expand Up @@ -1351,6 +1353,16 @@ void Settings::setIconTheme(IconTheme iconTheme) {
save();
}

auto Settings::getThemeVariant() const -> ThemeVariant { return this->themeVariant; }

void Settings::setThemeVariant(ThemeVariant theme) {
if (this->themeVariant == theme) {
return;
}
this->themeVariant = theme;
save();
}

auto Settings::getSidebarNumberingStyle() const -> SidebarNumberingStyle { return this->sidebarNumberingStyle; };

void Settings::setSidebarNumberingStyle(SidebarNumberingStyle numberingStyle) {
Expand Down Expand Up @@ -1832,16 +1844,6 @@ void Settings::setDisplayDpi(int dpi) {

auto Settings::getDisplayDpi() const -> int { return this->displayDpi; }

void Settings::setDarkTheme(bool dark) {
if (this->darkTheme == dark) {
return;
}
this->darkTheme = dark;
save();
}

auto Settings::isDarkTheme() const -> bool { return this->darkTheme; }

void Settings::setAreStockIconsUsed(bool use) {
if (this->useStockIcons == use) {
return;
Expand Down
20 changes: 8 additions & 12 deletions src/core/control/settings/Settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,6 @@ class Settings {
void setDisplayDpi(int dpi);
int getDisplayDpi() const;

/**
* Dark theme for white-coloured icons
*/
void setDarkTheme(bool dark);
bool isDarkTheme() const;

void setAreStockIconsUsed(bool use);
bool areStockIconsUsed() const;

Expand Down Expand Up @@ -322,6 +316,9 @@ class Settings {
IconTheme getIconTheme() const;
void setIconTheme(IconTheme iconTheme);

void setThemeVariant(ThemeVariant theme);
ThemeVariant getThemeVariant() const;

SidebarNumberingStyle getSidebarNumberingStyle() const;
void setSidebarNumberingStyle(SidebarNumberingStyle numberingStyle);

Expand Down Expand Up @@ -645,6 +642,11 @@ class Settings {
*/
IconTheme iconTheme;

/**
* Follow system's default theme variant or force one or the other
*/
ThemeVariant themeVariant;

/**
* Sidebar page number style
*/
Expand Down Expand Up @@ -676,12 +678,6 @@ class Settings {
*/
double cursorHighlightBorderWidth{};

/**
* If the user uses a dark-themed DE, he should enable this
* (white icons)
*/
bool darkTheme{};

/**
* If stock icons are used instead of Xournal++ icons when available
*/
Expand Down
14 changes: 14 additions & 0 deletions src/core/control/settings/SettingsEnums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,20 @@ auto iconThemeFromString(const std::string& iconThemeStr) -> IconTheme {
return ICON_THEME_COLOR;
}

auto themeVariantFromString(const std::string& themeVariantStr) -> ThemeVariant {
if (themeVariantStr == "useSystem") {
return THEME_VARIANT_USE_SYSTEM;
}
if (themeVariantStr == "forceLight") {
return THEME_VARIANT_FORCE_LIGHT;
}
if (themeVariantStr == "forceDark") {
return THEME_VARIANT_FORCE_DARK;
}
g_warning("Settings::Unknown theme variant: %s\n", themeVariantStr.c_str());
return THEME_VARIANT_USE_SYSTEM;
}

auto emptyLastPageAppendFromString(const std::string& str) -> EmptyLastPageAppendType {
if (str == "disabled") {
return EmptyLastPageAppendType::Disabled;
Expand Down
16 changes: 16 additions & 0 deletions src/core/control/settings/SettingsEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ enum IconTheme {
ICON_THEME_LUCIDE = 1,
};

enum ThemeVariant { THEME_VARIANT_USE_SYSTEM, THEME_VARIANT_FORCE_LIGHT, THEME_VARIANT_FORCE_DARK };

/**
* The user-selectable Page Preview Decoration style
*/
Expand Down Expand Up @@ -165,6 +167,19 @@ constexpr auto iconThemeToString(IconTheme iconTheme) -> const char* {
}
}

constexpr auto themeVariantToString(ThemeVariant variant) -> const char* {
switch (variant) {
case THEME_VARIANT_USE_SYSTEM:
return "useSystem";
case THEME_VARIANT_FORCE_LIGHT:
return "forceLight";
case THEME_VARIANT_FORCE_DARK:
return "forceDark";
default:
return "unknown";
}
}

constexpr auto emptyLastPageAppendToString(EmptyLastPageAppendType appendType) -> const char* {
switch (appendType) {
case EmptyLastPageAppendType::Disabled:
Expand All @@ -181,4 +196,5 @@ constexpr auto emptyLastPageAppendToString(EmptyLastPageAppendType appendType) -
StylusCursorType stylusCursorTypeFromString(const std::string& stylusCursorTypeStr);
EraserVisibility eraserVisibilityFromString(const std::string& eraserVisibilityStr);
IconTheme iconThemeFromString(const std::string& iconThemeStr);
ThemeVariant themeVariantFromString(const std::string& themeVariantStr);
EmptyLastPageAppendType emptyLastPageAppendFromString(const std::string& str);
72 changes: 67 additions & 5 deletions src/core/gui/MainWindow.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#include "MainWindow.h"

#include <config-dev.h> // for TOOLBAR_CONFIG
#include <gdk-pixbuf/gdk-pixbuf.h> // for gdk_pixbuf_new_fr...
#include <gdk/gdk.h> // for gdk_screen_get_de...
#include <gio/gio.h> // for g_cancellable_is_...
Expand Down Expand Up @@ -39,6 +38,7 @@
#include "GladeSearchpath.h" // for GladeSearchpath
#include "ToolbarDefinitions.h" // for TOOLBAR_DEFINITIO...
#include "XournalView.h" // for XournalView
#include "config-dev.h" // for TOOLBAR_CONFIG
#include "filesystem.h" // for path, exists

using std::string;
Expand All @@ -59,9 +59,6 @@ MainWindow::MainWindow(GladeSearchpath* gladeSearchPath, Control* control, GtkAp
mainContentWidget.reset(get("boxContents"), xoj::util::ref);
sidebarWidget.reset(get("sidebar"), xoj::util::ref);

GtkSettings* appSettings = gtk_settings_get_default();
g_object_set(appSettings, "gtk-application-prefer-dark-theme", control->getSettings()->isDarkTheme(), NULL);

loadMainCSS(gladeSearchPath, "xournalpp.css");

GtkOverlay* overlay = GTK_OVERLAY(get("mainOverlay"));
Expand Down Expand Up @@ -198,14 +195,64 @@ void MainWindow::toggleMenuBar(MainWindow* win) {
}

void MainWindow::updateColorscheme() {
bool darkMode = control->getSettings()->isDarkTheme();
if (control->getSettings()->getThemeVariant() == THEME_VARIANT_USE_SYSTEM) {
gtk_settings_reset_property(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme");
}

bool darkMode = isDarkTheme();

// Set up icons
{
const auto uiPath = this->getGladeSearchPath()->getFirstSearchPath();
const auto lightColorIcons = (uiPath / "iconsColor-light").u8string();
const auto darkColorIcons = (uiPath / "iconsColor-dark").u8string();
const auto lightLucideIcons = (uiPath / "iconsLucide-light").u8string();
const auto darkLucideIcons = (uiPath / "iconsLucide-dark").u8string();

// icon load order from lowest priority to highest priority
std::vector<std::string> iconLoadOrder = {};
const auto chosenTheme = control->getSettings()->getIconTheme();
switch (chosenTheme) {
case ICON_THEME_COLOR:
iconLoadOrder = {darkLucideIcons, lightLucideIcons, darkColorIcons, lightColorIcons};
break;
case ICON_THEME_LUCIDE:
iconLoadOrder = {darkColorIcons, lightColorIcons, darkLucideIcons, lightLucideIcons};
break;
default:
g_message("Unknown icon theme!");
}

if (darkMode) {
for (size_t i = 0; 2 * i + 1 < iconLoadOrder.size(); ++i) {
std::swap(iconLoadOrder[2 * i], iconLoadOrder[2 * i + 1]);
}
}

for (auto& p: iconLoadOrder) {
gtk_icon_theme_prepend_search_path(gtk_icon_theme_get_default(), p.c_str());
}
}

GtkStyleContext* context = gtk_widget_get_style_context(GTK_WIDGET(this->window));

if (darkMode) {
gtk_style_context_add_class(context, "darkMode");
g_object_set(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", true, nullptr);
} else {
gtk_style_context_remove_class(context, "darkMode");
g_object_set(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", false, nullptr);
}
assert([&]() {
gchar* name = nullptr;
g_object_get(gtk_widget_get_settings(this->window), "gtk-theme-name", &name, nullptr);
g_message("Theme name: %s", name);
g_free(name);
gboolean gtkdark = true;
g_object_get(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", &gtkdark, nullptr);
g_message("Theme variant: %s", gtkdark ? "dark" : "light");
return true;
}());
}

void MainWindow::initXournalWidget() {
Expand Down Expand Up @@ -538,6 +585,21 @@ void MainWindow::setMaximized(bool maximized) { this->maximized = maximized; }

auto MainWindow::isMaximized() const -> bool { return this->maximized; }

auto MainWindow::isDarkTheme() const -> bool {
switch (control->getSettings()->getThemeVariant()) {
case THEME_VARIANT_USE_SYSTEM: {
gboolean dark = false;
g_object_get(gtk_widget_get_settings(this->window), "gtk-application-prefer-dark-theme", &dark, nullptr);
return dark;
}
case THEME_VARIANT_FORCE_LIGHT:
return false;
case THEME_VARIANT_FORCE_DARK:
return true;
break;
}
}

auto MainWindow::getXournal() const -> XournalView* { return xournal.get(); }

auto MainWindow::windowMaximizedCallback(GObject* window, GParamSpec*, MainWindow* win) -> void {
Expand Down
2 changes: 2 additions & 0 deletions src/core/gui/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,8 @@ class MainWindow: public GladeGui, public LayerCtrlListener {
void setMaximized(bool maximized);
bool isMaximized() const;

bool isDarkTheme() const;

XournalView* getXournal() const;

void setMenubarVisible(bool visible);
Expand Down
3 changes: 2 additions & 1 deletion src/core/gui/PagePreviewDecoration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include "control/Control.h"
#include "control/settings/Settings.h"
#include "gui/MainWindow.h"
#include "util/raii/CairoWrappers.h"

void PagePreviewDecoration::drawDecoration(cairo_t* cr, SidebarPreviewPageEntry* pageEntry, Control* control) {
Expand All @@ -27,7 +28,7 @@ void PagePreviewDecoration::drawPageNumberBelowPreview(cairo_t* cr, SidebarPrevi
xoj::util::CairoSaveGuard saveGuard(cr);
cairo_text_extents_t extents;
std::string pageNumber = std::to_string(pageEntry->getIndex() + 1);
Color color = control->getSettings()->isDarkTheme() ? Colors::white : Colors::xopp_darkslategray;
Color color = control->getWindow()->isDarkTheme() ? Colors::white : Colors::xopp_darkslategray;
if (pageEntry->isSelected()) {
color = control->getSettings()->getBorderColor();
}
Expand Down
Loading

0 comments on commit 6166a29

Please sign in to comment.