diff --git a/pcsx2-qt/CMakeLists.txt b/pcsx2-qt/CMakeLists.txt index 4371e84282..5840b74403 100644 --- a/pcsx2-qt/CMakeLists.txt +++ b/pcsx2-qt/CMakeLists.txt @@ -21,6 +21,8 @@ target_sources(pcsx2-qt PRIVATE DisplayWidget.cpp DisplayWidget.h EarlyHardwareCheck.cpp + LogWindow.cpp + LogWindow.h MainWindow.cpp MainWindow.h MainWindow.ui diff --git a/pcsx2-qt/LogWindow.cpp b/pcsx2-qt/LogWindow.cpp new file mode 100644 index 0000000000..1d3861f37e --- /dev/null +++ b/pcsx2-qt/LogWindow.cpp @@ -0,0 +1,399 @@ +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team +// SPDX-License-Identifier: LGPL-3.0+ + +#include "LogWindow.h" +#include "MainWindow.h" +#include "QtHost.h" +#include "SettingWidgetBinder.h" + +#include +#include +#include +#include +#include + +#include + +// Need a lock so the other threads don't try to write to a deleting window. +LogWindow* g_log_window; +static std::mutex s_log_mutex; + +static LOGLEVEL GetWindowLogLevel() +{ +#ifdef _DEBUG + return LOGLEVEL_DEBUG; +#else + return (IsDevBuild || Host::GetBaseBoolSettingValue("Logging", "EnableVerbose", false)) ? LOGLEVEL_DEV : LOGLEVEL_INFO; +#endif +} + +LogWindow::LogWindow(bool attach_to_main) + : QMainWindow() + , m_attached_to_main_window(attach_to_main) +{ + restoreSize(); + createUi(); + + Log::SetHostOutputLevel(GetWindowLogLevel(), &LogWindow::logCallback); +} + +LogWindow::~LogWindow() +{ + Log::SetHostOutputLevel(LOGLEVEL_NONE, nullptr); +} + +void LogWindow::updateSettings() +{ + std::unique_lock lock(s_log_mutex); + + const bool new_enabled = Host::GetBaseBoolSettingValue("Logging", "EnableLogWindow", false) && !QtHost::InNoGUIMode(); + const bool attach_to_main = Host::GetBaseBoolSettingValue("Logging", "AttachLogWindowToMainWindow", true); + const bool curr_enabled = Log::IsHostOutputEnabled(); + + if (new_enabled == curr_enabled) + { + if (g_log_window && g_log_window->m_attached_to_main_window != attach_to_main) + { + g_log_window->m_attached_to_main_window = attach_to_main; + if (attach_to_main) + g_log_window->reattachToMainWindow(); + } + + // Update level. + if (new_enabled) + Log::SetHostOutputLevel(GetWindowLogLevel(), &LogWindow::logCallback); + + return; + } + + if (new_enabled) + { + g_log_window = new LogWindow(attach_to_main); + if (attach_to_main && g_main_window && g_main_window->isVisible()) + g_log_window->reattachToMainWindow(); + + g_log_window->show(); + } + else if (g_log_window) + { + g_log_window->m_destroying = true; + g_log_window->close(); + g_log_window->deleteLater(); + g_log_window = nullptr; + } +} + +void LogWindow::destroy() +{ + std::unique_lock lock(s_log_mutex); + if (!g_log_window) + return; + + g_log_window->m_destroying = true; + g_log_window->close(); + g_log_window->deleteLater(); + g_log_window = nullptr; +} + +void LogWindow::reattachToMainWindow() +{ + // Skip when maximized. + if (g_main_window->windowState() & (Qt::WindowMaximized | Qt::WindowFullScreen)) + return; + + resize(width(), g_main_window->height()); + + const QPoint new_pos = g_main_window->pos() + QPoint(g_main_window->width() + 10, 0); + if (pos() != new_pos) + move(new_pos); +} + +void LogWindow::updateWindowTitle() +{ + QString title; + + const QString& serial = QtHost::GetCurrentGameSerial(); + + if (QtHost::IsVMValid() && !serial.isEmpty()) + { + const QFileInfo fi(QtHost::GetCurrentGamePath()); + title = tr("Log Window - %1 [%2]").arg(serial).arg(fi.fileName()); + } + else + { + title = tr("Log Window"); + } + + setWindowTitle(title); +} + +void LogWindow::createUi() +{ + setWindowIcon(QtHost::GetAppIcon()); + updateWindowTitle(); + + QAction* action; + + QMenuBar* menu = new QMenuBar(this); + setMenuBar(menu); + + QMenu* log_menu = menu->addMenu("&Log"); + action = log_menu->addAction(tr("&Clear")); + connect(action, &QAction::triggered, this, &LogWindow::onClearTriggered); + action = log_menu->addAction(tr("&Save...")); + connect(action, &QAction::triggered, this, &LogWindow::onSaveTriggered); + + log_menu->addSeparator(); + + action = log_menu->addAction(tr("Cl&ose")); + connect(action, &QAction::triggered, this, &LogWindow::close); + + QMenu* settings_menu = menu->addMenu(tr("&Settings")); + +#if 0 + // TODO: These are duplicated with the main window... + action = settings_menu->addAction(tr("Log To &System Console")); + action->setCheckable(true); + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableSystemConsole", false); + + action = settings_menu->addAction(tr("Log To &Debug Console")); + action->setCheckable(true); + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableDebugConsole", false); + + action = settings_menu->addAction(tr("Log To &File")); + action->setCheckable(true); + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableFileLogging", false); + + settings_menu->addSeparator(); +#endif + + action = settings_menu->addAction(tr("Attach To &Main Window")); + action->setCheckable(true); + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "AttachLogWindowToMainWindow", true); + + action = settings_menu->addAction(tr("Show &Timestamps")); + action->setCheckable(true); + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, action, "Logging", "EnableTimestamps", true); + + settings_menu->addSeparator(); + + // TODO: Log Level + + m_text = new QPlainTextEdit(this); + m_text->setReadOnly(true); + m_text->setUndoRedoEnabled(false); + m_text->setTextInteractionFlags(Qt::TextSelectableByKeyboard | Qt::TextSelectableByMouse); + m_text->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + m_text->setWordWrapMode(QTextOption::WrapAnywhere); + +#if defined(_WIN32) + QFont font("Consolas"); + font.setPointSize(10); +#elif defined(__APPLE__) + QFont font("Monaco"); + font.setPointSize(11); +#else + QFont font("Monospace"); + font.setStyleHint(QFont::TypeWriter); +#endif + m_text->setFont(font); + + setCentralWidget(m_text); +} + +void LogWindow::onClearTriggered() +{ + m_text->clear(); +} + +void LogWindow::onSaveTriggered() +{ + const QString path = QFileDialog::getSaveFileName(this, tr("Select Log File"), QString(), tr("Log Files (*.txt)")); + if (path.isEmpty()) + return; + + QFile file(path); + if (!file.open(QFile::WriteOnly | QFile::Text)) + { + QMessageBox::critical(this, tr("Error"), tr("Failed to open file for writing.")); + return; + } + + file.write(m_text->toPlainText().toUtf8()); + file.close(); + + appendMessage(LOGLEVEL_INFO, Color_Default, tr("Log was written to %1.\n").arg(path)); +} + +void LogWindow::logCallback(LOGLEVEL level, ConsoleColors color, std::string_view message) +{ + std::unique_lock lock(s_log_mutex); + if (!g_log_window) + return; + + // I don't like the memory allocations here either... + QString qmessage; + qmessage.reserve(message.length() + 1); + qmessage.append(QUtf8StringView(message.data(), message.length())); + qmessage.append(QChar('\n')); + + if (g_emu_thread->isOnUIThread()) + { + g_log_window->appendMessage(static_cast(level), static_cast(color), qmessage); + } + else + { + QMetaObject::invokeMethod(g_log_window, "appendMessage", Qt::QueuedConnection, + Q_ARG(quint32, static_cast(level)), Q_ARG(quint32, static_cast(color)), + Q_ARG(const QString&, qmessage)); + } +} + +void LogWindow::closeEvent(QCloseEvent* event) +{ + Log::SetHostOutputLevel(LOGLEVEL_NONE, nullptr); + + // Save size when actually closing, disable ourselves if the user closed us. + if (m_destroying) + { + saveSize(); + } + else + { + Host::SetBaseBoolSettingValue("Logging", "EnableLogWindow", false); + Host::CommitBaseSettingChanges(); + } + + QMainWindow::closeEvent(event); +} + +void LogWindow::appendMessage(quint32 level, quint32 color, const QString& message) +{ + QTextCursor temp_cursor = m_text->textCursor(); + QScrollBar* scrollbar = m_text->verticalScrollBar(); + const bool cursor_at_end = temp_cursor.atEnd(); + const bool scroll_at_end = scrollbar->sliderPosition() == scrollbar->maximum(); + + temp_cursor.movePosition(QTextCursor::End); + + { + static constexpr const QColor qcolors[2][ConsoleColors_Count] = { + // Light theme + { + QColor(0, 0, 0), // Color_Default + QColor(0, 0, 0), // Color_Black + QColor(128, 0, 0), // Color_Red + QColor(0, 128, 0), // Color_Green + QColor(0, 0, 128), // Color_Blue + QColor(160, 0, 160), // Color_Magenta + QColor(160, 120, 0), // Color_Orange + QColor(108, 108, 108), // Color_Gray + + QColor(128, 180, 180), // Color_Cyan + QColor(180, 180, 128), // Color_Yellow + QColor(160, 160, 160), // Color_White + + QColor(0, 0, 0), // Color_StrongBlack + QColor(128, 0, 0), // Color_StrongRed + QColor(0, 128, 0), // Color_StrongGreen + QColor(0, 0, 128), // Color_StrongBlue + QColor(160, 0, 160), // Color_StrongMagenta + QColor(160, 120, 0), // Color_StrongOrange + QColor(108, 108, 108), // Color_StrongGray + + QColor(128, 180, 180), // Color_StrongCyan + QColor(180, 180, 128), // Color_StrongYellow + QColor(160, 160, 160), // Color_StrongWhite + }, + // Dark theme + { + QColor(208, 208, 208), // Color_Default + QColor(255, 255, 255), // Color_Black + QColor(180, 0, 0), // Color_Red + QColor(0, 160, 0), // Color_Green + QColor(32, 32, 204), // Color_Blue + QColor(160, 0, 160), // Color_Magenta + QColor(160, 120, 0), // Color_Orange + QColor(128, 128, 128), // Color_Gray + QColor(128, 180, 180), // Color_Cyan + QColor(180, 180, 128), // Color_Yellow + QColor(160, 160, 160), // Color_White + QColor(255, 255, 255), // Color_StrongBlack + QColor(180, 0, 0), // Color_StrongRed + QColor(0, 160, 0), // Color_StrongGreen + QColor(32, 32, 204), // Color_StrongBlue + QColor(160, 0, 160), // Color_StrongMagenta + QColor(160, 120, 0), // Color_StrongOrange + QColor(128, 128, 128), // Color_StrongGray + QColor(128, 180, 180), // Color_StrongCyan + QColor(180, 180, 128), // Color_StrongYellow + QColor(160, 160, 160), // Color_StrongWhite + }, + }; + + static constexpr const QColor timestamp_color = QColor(0xcc, 0xcc, 0xcc); + + QTextCharFormat format = temp_cursor.charFormat(); + + if (Log::AreTimestampsEnabled()) + { + const float message_time = Log::GetCurrentMessageTime(); + const QString qtimestamp = QStringLiteral("[%1] ").arg(message_time, 10, 'f', 4); + format.setForeground(QBrush(timestamp_color)); + temp_cursor.setCharFormat(format); + temp_cursor.insertText(qtimestamp); + } + + const bool dark = static_cast(QtHost::IsDarkApplicationTheme()); + + // message has \n already + format.setForeground(QBrush(qcolors[static_cast(dark)][color])); + temp_cursor.setCharFormat(format); + temp_cursor.insertText(message); + } + + if (cursor_at_end) + { + if (scroll_at_end) + { + m_text->setTextCursor(temp_cursor); + scrollbar->setSliderPosition(scrollbar->maximum()); + } + else + { + // Can't let changing the cursor affect the scroll bar... + const int pos = scrollbar->sliderPosition(); + m_text->setTextCursor(temp_cursor); + scrollbar->setSliderPosition(pos); + } + } +} + +void LogWindow::saveSize() +{ + const int current_width = Host::GetBaseIntSettingValue("UI", "LogWindowWidth", DEFAULT_WIDTH); + const int current_height = Host::GetBaseIntSettingValue("UI", "LogWindowHeight", DEFAULT_HEIGHT); + const QSize wsize = size(); + + bool changed = false; + if (current_width != wsize.width()) + { + Host::SetBaseIntSettingValue("UI", "LogWindowWidth", wsize.width()); + changed = true; + } + if (current_height != wsize.height()) + { + Host::SetBaseIntSettingValue("UI", "LogWindowHeight", wsize.height()); + changed = true; + } + + if (changed) + Host::CommitBaseSettingChanges(); +} + +void LogWindow::restoreSize() +{ + const int width = Host::GetBaseIntSettingValue("UI", "LogWindowWidth", DEFAULT_WIDTH); + const int height = Host::GetBaseIntSettingValue("UI", "LogWindowHeight", DEFAULT_HEIGHT); + resize(width, height); +} diff --git a/pcsx2-qt/LogWindow.h b/pcsx2-qt/LogWindow.h new file mode 100644 index 0000000000..942ec3c231 --- /dev/null +++ b/pcsx2-qt/LogWindow.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team +// SPDX-License-Identifier: LGPL-3.0+ + +#pragma once + +#include "common/Console.h" + +#include +#include + +class LogWindow : public QMainWindow +{ + Q_OBJECT + +public: + LogWindow(bool attach_to_main); + ~LogWindow(); + + static void updateSettings(); + static void destroy(); + + __fi bool isAttachedToMainWindow() const { return m_attached_to_main_window; } + void reattachToMainWindow(); + + void updateWindowTitle(); + +private: + void createUi(); + + static void logCallback(LOGLEVEL level, ConsoleColors color, std::string_view message); + +protected: + void closeEvent(QCloseEvent* event); + +private Q_SLOTS: + void onClearTriggered(); + void onSaveTriggered(); + void appendMessage(quint32 level, quint32 color, const QString& message); + +private: + static constexpr int DEFAULT_WIDTH = 750; + static constexpr int DEFAULT_HEIGHT = 400; + + void saveSize(); + void restoreSize(); + + QPlainTextEdit* m_text; + QMenu* m_level_menu; + + bool m_attached_to_main_window = true; + bool m_destroying = false; +}; + +extern LogWindow* g_log_window; diff --git a/pcsx2-qt/MainWindow.cpp b/pcsx2-qt/MainWindow.cpp index 848fcb6f42..c113233347 100644 --- a/pcsx2-qt/MainWindow.cpp +++ b/pcsx2-qt/MainWindow.cpp @@ -7,6 +7,7 @@ #include "DisplayWidget.h" #include "GameList/GameListRefreshThread.h" #include "GameList/GameListWidget.h" +#include "LogWindow.h" #include "MainWindow.h" #include "QtHost.h" #include "QtUtils.h" @@ -255,7 +256,7 @@ void MainWindow::setupAdditionalUi() #ifdef ENABLE_RAINTEGRATION if (Achievements::IsUsingRAIntegration()) { - QMenu* raMenu = new QMenu(QStringLiteral("RAIntegration"), m_ui.menu_Tools); + QMenu* raMenu = new QMenu(QStringLiteral("RAIntegration"), m_ui.menuTools); connect(raMenu, &QMenu::aboutToShow, this, [this, raMenu]() { raMenu->clear(); @@ -279,7 +280,7 @@ void MainWindow::setupAdditionalUi() [id = id]() { Host::RunOnCPUThread([id]() { Achievements::RAIntegration::ActivateMenuItem(id); }, false); }); } }); - m_ui.menu_Tools->insertMenu(m_ui.menuInput_Recording->menuAction(), raMenu); + m_ui.menuTools->insertMenu(m_ui.menuInputRecording->menuAction(), raMenu); } #endif } @@ -366,6 +367,14 @@ void MainWindow::connectSignals() SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionViewStatusBarVerbose, "UI", "VerboseStatusBar", false); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableSystemConsole, "Logging", "EnableSystemConsole", false); +#ifdef _WIN32 + // Debug console only exists on Windows. + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableDebugConsole, "Logging", "EnableDebugConsole", false); +#else + m_ui.menuTools->removeAction(m_ui.actionEnableDebugConsole); + m_ui.actionEnableDebugConsole->deleteLater(); + m_ui.actionEnableDebugConsole = nullptr; +#endif #ifndef PCSX2_DEVBUILD SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableVerboseLogging, "Logging", "EnableVerbose", false); #else @@ -375,6 +384,7 @@ void MainWindow::connectSignals() #endif SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableEEConsoleLogging, "Logging", "EnableEEConsole", true); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableIOPConsoleLogging, "Logging", "EnableIOPConsole", true); + SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableLogWindow, "Logging", "EnableLogWindow", false); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableFileLogging, "Logging", "EnableFileLogging", false); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableLogTimestamps, "Logging", "EnableTimestamps", true); SettingWidgetBinder::BindWidgetToBoolSetting(nullptr, m_ui.actionEnableCDVDVerboseReads, "EmuCore", "CdvdVerboseReads", false); @@ -508,6 +518,11 @@ void MainWindow::recreate() new_main_window->show(); deleteLater(); + // Recreate log window as well. Then make sure we're still on top. + LogWindow::updateSettings(); + new_main_window->raise(); + new_main_window->activateWindow(); + // Reload the sources we just closed. g_emu_thread->reloadInputSources(); @@ -579,6 +594,8 @@ void MainWindow::destroySubWindows() } SettingsWindow::closeGamePropertiesDialogs(); + + LogWindow::destroy(); } void MainWindow::onScreenshotActionTriggered() @@ -920,6 +937,9 @@ void MainWindow::updateWindowTitle() if (container->windowTitle() != display_title) container->setWindowTitle(display_title); } + + if (g_log_window) + g_log_window->updateWindowTitle(); } void MainWindow::updateWindowState(bool force_visible) @@ -1192,6 +1212,8 @@ void MainWindow::checkForSettingChanges() updateDisplayWidgetCursor(); updateWindowState(); + + LogWindow::updateSettings(); } std::optional MainWindow::getWindowInfo() @@ -2041,6 +2063,22 @@ void MainWindow::dropEvent(QDropEvent* event) } } +void MainWindow::moveEvent(QMoveEvent* event) +{ + QMainWindow::moveEvent(event); + + if (g_log_window && g_log_window->isAttachedToMainWindow()) + g_log_window->reattachToMainWindow(); +} + +void MainWindow::resizeEvent(QResizeEvent* event) +{ + QMainWindow::resizeEvent(event); + + if (g_log_window && g_log_window->isAttachedToMainWindow()) + g_log_window->reattachToMainWindow(); +} + void MainWindow::registerForDeviceNotifications() { #ifdef _WIN32 diff --git a/pcsx2-qt/MainWindow.h b/pcsx2-qt/MainWindow.h index 81a72da43d..1934305046 100644 --- a/pcsx2-qt/MainWindow.h +++ b/pcsx2-qt/MainWindow.h @@ -197,15 +197,14 @@ protected: void changeEvent(QEvent* event) override; void dragEnterEvent(QDragEnterEvent* event) override; void dropEvent(QDropEvent* event) override; + void moveEvent(QMoveEvent* event) override; + void resizeEvent(QResizeEvent* event) override; #ifdef _WIN32 bool nativeEvent(const QByteArray& eventType, void* message, qintptr* result) override; #endif private: - static void setStyleFromSettings(); - static void setIconThemeFromStyle(); - void setupAdditionalUi(); void connectSignals(); void createRendererSwitchMenu(); diff --git a/pcsx2-qt/MainWindow.ui b/pcsx2-qt/MainWindow.ui index d846d185e7..9ee227e9e8 100644 --- a/pcsx2-qt/MainWindow.ui +++ b/pcsx2-qt/MainWindow.ui @@ -146,7 +146,7 @@ - + &View @@ -176,11 +176,11 @@ - + &Tools - + Input Recording @@ -206,10 +206,12 @@ - + + + @@ -219,8 +221,8 @@ - - + + @@ -901,6 +903,22 @@ Enable System Console + + + true + + + Enable Debug Console + + + + + true + + + Enable Log Window + + true diff --git a/pcsx2-qt/QtHost.cpp b/pcsx2-qt/QtHost.cpp index 45a1f622d0..e9d3271801 100644 --- a/pcsx2-qt/QtHost.cpp +++ b/pcsx2-qt/QtHost.cpp @@ -4,6 +4,7 @@ #include "AutoUpdaterDialog.h" #include "DisplayWidget.h" #include "GameList/GameListWidget.h" +#include "LogWindow.h" #include "MainWindow.h" #include "QtHost.h" #include "QtProgressCallback.h" @@ -101,11 +102,6 @@ EmuThread::EmuThread(QThread* ui_thread) EmuThread::~EmuThread() = default; -bool EmuThread::isOnEmuThread() const -{ - return QThread::currentThread() == this; -} - void EmuThread::start() { pxAssertRel(!g_emu_thread, "Emu thread does not exist"); @@ -1918,6 +1914,9 @@ int main(int argc, char* argv[]) // Set theme before creating any windows. QtHost::UpdateApplicationTheme(); + // Start logging early. + LogWindow::updateSettings(); + // Start up the CPU thread. QtHost::HookSignals(); EmuThread::start(); @@ -1942,7 +1941,11 @@ int main(int argc, char* argv[]) // Don't bother showing the window in no-gui mode. if (!s_nogui_mode) + { g_main_window->show(); + g_main_window->raise(); + g_main_window->activateWindow(); + } // Initialize big picture mode if requested. if (s_start_fullscreen_ui) diff --git a/pcsx2-qt/QtHost.h b/pcsx2-qt/QtHost.h index 07994fc82e..b5b756d8c1 100644 --- a/pcsx2-qt/QtHost.h +++ b/pcsx2-qt/QtHost.h @@ -63,7 +63,8 @@ public: __fi bool isSurfaceless() const { return m_is_surfaceless; } __fi bool isRunningFullscreenUI() const { return m_run_fullscreen_ui; } - bool isOnEmuThread() const; + __fi bool isOnEmuThread() const { return (QThread::currentThread() == this); } + __fi bool isOnUIThread() const { return (QThread::currentThread() == m_ui_thread); } bool shouldRenderToMain() const; /// Called back from the GS thread when the display state changes (e.g. fullscreen, render to main). @@ -237,6 +238,9 @@ namespace QtHost /// Sets application theme according to settings. void UpdateApplicationTheme(); + /// Returns true if the application theme is using dark colours. + bool IsDarkApplicationTheme(); + /// Sets the icon theme, based on the current style (light/dark). void SetIconThemeFromStyle(); diff --git a/pcsx2-qt/Themes.cpp b/pcsx2-qt/Themes.cpp index 5b29e3ba28..53445e9109 100644 --- a/pcsx2-qt/Themes.cpp +++ b/pcsx2-qt/Themes.cpp @@ -476,9 +476,14 @@ void QtHost::SetStyleFromSettings() } } -void QtHost::SetIconThemeFromStyle() +bool QtHost::IsDarkApplicationTheme() { QPalette palette = qApp->palette(); - bool dark = palette.windowText().color().value() > palette.window().color().value(); + return (palette.windowText().color().value() > palette.window().color().value()); +} + +void QtHost::SetIconThemeFromStyle() +{ + const bool dark = IsDarkApplicationTheme(); QIcon::setThemeName(dark ? QStringLiteral("white") : QStringLiteral("black")); } diff --git a/pcsx2-qt/pcsx2-qt.vcxproj b/pcsx2-qt/pcsx2-qt.vcxproj index d461c1f1ed..b72e7522f9 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj +++ b/pcsx2-qt/pcsx2-qt.vcxproj @@ -89,6 +89,7 @@ + @@ -172,6 +173,7 @@ + @@ -262,6 +264,7 @@ + diff --git a/pcsx2-qt/pcsx2-qt.vcxproj.filters b/pcsx2-qt/pcsx2-qt.vcxproj.filters index 140cd153da..c5b868ba42 100644 --- a/pcsx2-qt/pcsx2-qt.vcxproj.filters +++ b/pcsx2-qt/pcsx2-qt.vcxproj.filters @@ -342,6 +342,10 @@ moc + + + moc + @@ -499,6 +503,7 @@ Settings +