Qt: adjust ansi colors based on background color
Some checks failed
Generate Translation Template / Generate Translation Template (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux-aarch64.sh, gcc, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (/rpcs3/.ci/build-linux.sh, gcc, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1, rpcs3/rpcs3-binaries-linux-arm64, /rpcs3/.ci/build-linux-aarch64.sh, clang, rpcs3/rpcs3-ci-jammy-aarch64:1.7, ubuntu-24.04-arm) (push) Has been cancelled
Build RPCS3 / RPCS3 Linux ${{ matrix.os }} ${{ matrix.compiler }} (d812f1254a1157c80fd402f94446310560f54e5f, rpcs3/rpcs3-binaries-linux, /rpcs3/.ci/build-linux.sh, clang, rpcs3/rpcs3-ci-jammy:1.7, ubuntu-24.04) (push) Has been cancelled
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (0, 51ae32f468089a8169aaf1567de355ff4a3e0842, rpcs3/rpcs3-binaries-mac, Intel) (push) Has been cancelled
Build RPCS3 / RPCS3 Mac ${{ matrix.name }} (1, 8e21bdbc40711a3fccd18fbf17b742348b0f4281, rpcs3/rpcs3-binaries-mac-arm64, Apple Silicon) (push) Has been cancelled
Build RPCS3 / RPCS3 Windows (push) Has been cancelled
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (aarch64, clang, clangarm64, ARM64, windows-11-arm) (push) Has been cancelled
Build RPCS3 / RPCS3 Windows Clang ${{ matrix.arch }} (x86_64, clang, clang64, X64, windows-2025) (push) Has been cancelled
Build RPCS3 / RPCS3 FreeBSD (push) Has been cancelled

This commit is contained in:
Megamouse 2026-02-08 18:31:31 +01:00
parent 4c234dc744
commit 8f066541a3
5 changed files with 100 additions and 46 deletions

View file

@ -220,7 +220,7 @@ void log_frame::CreateAndConnectActions()
// I, for one, welcome our lambda overlord
// It's either this or a signal mapper
// Then, probably making a list of these actions so that it's easier to iterate to generate the mapper.
auto l_initAct = [this](QAction* act, logs::level logLevel)
const auto l_initAct = [this](QAction* act, logs::level logLevel)
{
act->setCheckable(true);
@ -293,7 +293,7 @@ void log_frame::CreateAndConnectActions()
if (m_ansi_tty && !m_tty_ansi_highlighter)
{
m_tty_ansi_highlighter = new AnsiHighlighter(m_tty->document());
m_tty_ansi_highlighter = new AnsiHighlighter(m_tty);
}
else if (!m_ansi_tty && m_tty_ansi_highlighter)
{
@ -602,6 +602,12 @@ void log_frame::RepaintTextColors()
html.replace(old_style, new_style);
m_log->document()->setHtml(html);
if (m_tty_ansi_highlighter)
{
m_tty_ansi_highlighter->update_colors(m_tty);
m_tty_ansi_highlighter->rehighlight();
}
}
void log_frame::UpdateUI()

View file

@ -173,21 +173,45 @@ namespace gui
}
return res;
}
QColor get_foreground_color()
QColor get_foreground_color(QWidget* widget)
{
if (widget)
{
widget->ensurePolished();
return widget->palette().color(QPalette::ColorRole::WindowText);
}
QLabel dummy_color;
dummy_color.ensurePolished();
return dummy_color.palette().color(QPalette::ColorRole::WindowText);
}
QColor get_background_color()
QColor get_background_color(QWidget* widget)
{
if (widget)
{
widget->ensurePolished();
return widget->palette().color(QPalette::ColorRole::Window);
}
QLabel dummy_color;
dummy_color.ensurePolished();
return dummy_color.palette().color(QPalette::ColorRole::Window);
}
QColor adjust_color_for_background(const QColor& fg, const QColor& bg)
{
const int diff = fg.lightness() - bg.lightness();
if (std::abs(diff) >= 40)
{
return fg;
}
return (bg.lightness() < 128) ? fg.lighter(180) : fg.darker(180);
}
QColor get_label_color(const QString& object_name, const QColor& fallback_light, const QColor& fallback_dark, QPalette::ColorRole color_role)
{
if (!gui::custom_stylesheet_active || !gui::stylesheet.contains(object_name))

View file

@ -68,11 +68,14 @@ namespace gui
// Returns a list of all base names of files in dir whose complete file names contain one of the given name_filters
QStringList get_dir_entries(const QDir& dir, const QStringList& name_filters, bool full_path = false);
// Returns the foreground color of QLabel with respect to the current light/dark mode.
QColor get_foreground_color();
// Returns the foreground color of QLabel or the given widget with respect to the current light/dark mode.
QColor get_foreground_color(QWidget* widget = nullptr);
// Returns the background color of QLabel with respect to the current light/dark mode.
QColor get_background_color();
// Returns the background color of QLabel or the given widget with respect to the current light/dark mode.
QColor get_background_color(QWidget* widget = nullptr);
// Returns an adjusted color with better contrast, depending on the background.
QColor adjust_color_for_background(const QColor& fg, const QColor& bg);
// Returns the color specified by its color_role for the QLabels with object_name
QColor get_label_color(const QString& object_name, const QColor& fallback_light, const QColor& fallback_dark, QPalette::ColorRole color_role = QPalette::WindowText);

View file

@ -184,12 +184,37 @@ GlslHighlighter::GlslHighlighter(QTextDocument* parent) : Highlighter(parent)
commentEndExpression = QRegularExpression("\\*/");
}
AnsiHighlighter::AnsiHighlighter(QTextDocument* parent) : Highlighter(parent)
AnsiHighlighter::AnsiHighlighter(QPlainTextEdit* text_edit)
: Highlighter(text_edit ? text_edit->document() : nullptr)
{
m_escape_format.setForeground(Qt::darkGray);
m_escape_format.setFontItalic(true);
update_colors(text_edit);
}
m_foreground_color = gui::utils::get_foreground_color();
void AnsiHighlighter::update_colors(QPlainTextEdit* text_edit)
{
m_foreground_color = gui::utils::get_foreground_color(text_edit);
m_background_color = gui::utils::get_background_color(text_edit);
m_foreground_colors[30] = gui::utils::adjust_color_for_background(Qt::black, m_background_color);
m_foreground_colors[31] = gui::utils::adjust_color_for_background(Qt::red, m_background_color);
m_foreground_colors[32] = gui::utils::adjust_color_for_background(Qt::darkGreen, m_background_color);
m_foreground_colors[33] = gui::utils::adjust_color_for_background(Qt::darkYellow, m_background_color);
m_foreground_colors[34] = gui::utils::adjust_color_for_background(Qt::darkBlue, m_background_color);
m_foreground_colors[35] = gui::utils::adjust_color_for_background(Qt::darkMagenta, m_background_color);
m_foreground_colors[36] = gui::utils::adjust_color_for_background(Qt::darkCyan, m_background_color);
m_foreground_colors[37] = gui::utils::adjust_color_for_background(Qt::lightGray, m_background_color);
m_foreground_colors[39] = m_foreground_color;
m_foreground_colors[90] = gui::utils::adjust_color_for_background(Qt::darkGray, m_background_color);
m_foreground_colors[91] = gui::utils::adjust_color_for_background(Qt::red, m_background_color);
m_foreground_colors[92] = gui::utils::adjust_color_for_background(Qt::green, m_background_color);
m_foreground_colors[93] = gui::utils::adjust_color_for_background(Qt::yellow, m_background_color);
m_foreground_colors[94] = gui::utils::adjust_color_for_background(Qt::blue, m_background_color);
m_foreground_colors[95] = gui::utils::adjust_color_for_background(Qt::magenta, m_background_color);
m_foreground_colors[96] = gui::utils::adjust_color_for_background(Qt::cyan, m_background_color);
m_foreground_colors[97] = gui::utils::adjust_color_for_background(Qt::white, m_background_color);
m_escape_format.setForeground(gui::utils::adjust_color_for_background(Qt::darkGray, m_background_color));
m_escape_format.setFontItalic(true);
}
void AnsiHighlighter::highlightBlock(const QString& text)
@ -235,39 +260,26 @@ void AnsiHighlighter::highlightBlock(const QString& text)
if (!ok) continue;
switch (code)
{
case 0:
current_format = QTextCharFormat();
current_format.setForeground(m_foreground_color);
break;
case 1:
current_format.setFontWeight(QFont::Bold);
break;
case 3:
current_format.setFontItalic(true);
break;
case 4:
current_format.setFontUnderline(true);
break;
case 30: current_format.setForeground(Qt::black); break;
case 31: current_format.setForeground(Qt::red); break;
case 32: current_format.setForeground(Qt::darkGreen); break;
case 33: current_format.setForeground(Qt::darkYellow); break;
case 34: current_format.setForeground(Qt::darkBlue); break;
case 35: current_format.setForeground(Qt::darkMagenta); break;
case 36: current_format.setForeground(Qt::darkCyan); break;
case 37: current_format.setForeground(Qt::lightGray); break;
case 39: current_format.setForeground(m_foreground_color); break;
case 90: current_format.setForeground(Qt::darkGray); break;
case 91: current_format.setForeground(Qt::red); break;
case 92: current_format.setForeground(Qt::green); break;
case 93: current_format.setForeground(Qt::yellow); break;
case 94: current_format.setForeground(Qt::blue); break;
case 95: current_format.setForeground(Qt::magenta); break;
case 96: current_format.setForeground(Qt::cyan); break;
case 97: current_format.setForeground(Qt::white); break;
case 0:
current_format = QTextCharFormat();
current_format.setForeground(m_foreground_color);
break;
case 1:
current_format.setFontWeight(QFont::Bold);
break;
case 3:
current_format.setFontItalic(true);
break;
case 4:
current_format.setFontUnderline(true);
break;
default:
// Background and extended colors not yet handled
default:
break;
if (const auto it = m_foreground_colors.find(code); it != m_foreground_colors.cend())
{
current_format.setForeground(it->second);
}
break;
}
}
}
@ -278,5 +290,7 @@ void AnsiHighlighter::highlightBlock(const QString& text)
// Apply remaining format
if (pos < text.length())
{
setFormat(pos, text.length() - pos, current_format);
}
}

View file

@ -3,6 +3,9 @@
#include <QSyntaxHighlighter>
#include <QRegularExpression>
#include <QBrush>
#include <QPlainTextEdit>
#include <map>
// Inspired by https://doc.qt.io/qt-5/qtwidgets-richtext-syntaxhighlighter-example.html
@ -59,7 +62,9 @@ class AnsiHighlighter : public Highlighter
Q_OBJECT
public:
explicit AnsiHighlighter(QTextDocument* parent = nullptr);
explicit AnsiHighlighter(QPlainTextEdit* text_edit);
void update_colors(QPlainTextEdit* text_edit);
protected:
const QRegularExpression ansi_re = QRegularExpression("\x1b\\[[0-9;]*m");
@ -67,6 +72,8 @@ protected:
QTextCharFormat m_escape_format;
QColor m_foreground_color;
QColor m_background_color;
std::map<int, QColor> m_foreground_colors;
void highlightBlock(const QString& text) override;
};