diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index db26a75cb823..a15fe3b8228f 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -121,6 +121,14 @@ void EditorLog::_update_theme() { theme_cache.warning_color = get_theme_color(SNAME("warning_color"), EditorStringName(Editor)); theme_cache.warning_icon = get_editor_theme_icon(SNAME("Warning")); theme_cache.message_color = get_theme_color(SceneStringName(font_color), EditorStringName(Editor)) * Color(1, 1, 1, 0.6); + + // Used for `print_rich()` coloring. + theme_cache.red_color = get_theme_color(SNAME("red_color"), EditorStringName(Editor)); + theme_cache.green_color = get_theme_color(SNAME("green_color"), EditorStringName(Editor)); + theme_cache.yellow_color = get_theme_color(SNAME("yellow_color"), EditorStringName(Editor)); + theme_cache.blue_color = get_theme_color(SNAME("blue_color"), EditorStringName(Editor)); + theme_cache.magenta_color = get_theme_color(SNAME("magenta_color"), EditorStringName(Editor)); + theme_cache.cyan_color = get_theme_color(SNAME("cyan_color"), EditorStringName(Editor)); } void EditorLog::_editor_settings_changed() { @@ -243,7 +251,7 @@ void EditorLog::_process_message(const String &p_msg, MessageType p_type, bool p void EditorLog::add_message(const String &p_msg, MessageType p_type) { // Make text split by new lines their own message. - // See #41321 for reasoning. At time of writing, multiple print()'s in running projects + // See GH-41321 for reasoning. At time of writing, multiple print()'s in running projects // get grouped together and sent to the editor log as one message. This can mess with the // search functionality (see the comments on the PR above for more details). This behavior // also matches that of other IDE's. @@ -326,6 +334,58 @@ bool EditorLog::_check_display_message(LogMessage &p_message) { return filter_active && search_match; } +String EditorLog::_replace_color(const String &p_color) const { + // Replace colors with better-looking colors, which better match most terminal emulators out there. + if (p_color == "red") { + return theme_cache.red_color.to_html(); + } else if (p_color == "green") { + return theme_cache.green_color.to_html(); + } else if (p_color == "yellow") { + return theme_cache.yellow_color.to_html(); + } else if (p_color == "blue") { + return theme_cache.blue_color.to_html(); + } else if (p_color == "magenta") { + return theme_cache.magenta_color.to_html(); + } else if (p_color == "cyan") { + return theme_cache.cyan_color.to_html(); + } + + // Return other colors as-is. + return p_color; +} + +// Returns the string passed with BBCode colors replaced by better-looking color codes (according to the editor theme). +String EditorLog::_replace_bbcode_colors(const String &p_string) const { + String result; + int buffer_start = 0; + int from = 0; + + while (true) { + const int lb_pos = p_string.find_char('[', from); + if (lb_pos < 0) { + break; + } + + const int rb_pos = p_string.find_char(']', lb_pos + 1); + if (rb_pos < 0) { + break; + } + + const String tag = p_string.substr(lb_pos + 1, rb_pos - lb_pos - 1); + if (tag.begins_with("color=") || tag.begins_with("bgcolor=") || tag.begins_with("fgcolor=")) { + const int eq_pos = p_string.find_char('=', lb_pos + 1); + const String color = p_string.substr(eq_pos + 1, rb_pos - eq_pos - 1); + result += p_string.substr(buffer_start, eq_pos - buffer_start + 1) + _replace_color(color); + buffer_start = rb_pos; + } + from = rb_pos + 1; + } + + result += p_string.substr(buffer_start); + + return result; +} + void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) { if (!is_inside_tree()) { // The log will be built all at once when it enters the tree and has its theme items. @@ -382,7 +442,10 @@ void EditorLog::_add_log_line(LogMessage &p_message, bool p_replace_previous) { } if (p_message.type == MSG_TYPE_STD_RICH) { - log->append_text(p_message.text); + // Replace basic ANSI colors with more pleasant-looking colors, similar to what most terminals do out of the box. + // This also allows the printed colors to adapt to the current editor theme at the time of printing. + // Only replace the end of the color tag so that colors in `bgcolor` and `fgcolor` are replaced too. + log->append_text(_replace_bbcode_colors(p_message.text)); } else { log->add_text(p_message.text); } diff --git a/editor/editor_log.h b/editor/editor_log.h index 4f97416d0d35..d59e52eb8694 100644 --- a/editor/editor_log.h +++ b/editor/editor_log.h @@ -79,6 +79,13 @@ class EditorLog : public HBoxContainer { Ref warning_icon; Color message_color; + + Color red_color; + Color green_color; + Color yellow_color; + Color blue_color; + Color magenta_color; + Color cyan_color; } theme_cache; // Encapsulates all data and functionality regarding filters. @@ -162,6 +169,8 @@ class EditorLog : public HBoxContainer { void _rebuild_log(); void _add_log_line(LogMessage &p_message, bool p_replace_previous = false); bool _check_display_message(LogMessage &p_message); + String _replace_color(const String &p_color) const; + String _replace_bbcode_colors(const String &p_string) const; void _set_filter_active(bool p_active, MessageType p_message_type); void _set_search_visible(bool p_visible); diff --git a/editor/themes/editor_theme_manager.cpp b/editor/themes/editor_theme_manager.cpp index 7f3adbc1b608..652b6b02189e 100644 --- a/editor/themes/editor_theme_manager.cpp +++ b/editor/themes/editor_theme_manager.cpp @@ -433,11 +433,17 @@ void EditorThemeManager::_create_shared_styles(const Ref &p_theme, p_config.success_color = Color(0.45, 0.95, 0.5); p_config.warning_color = Color(1, 0.87, 0.4); p_config.error_color = Color(1, 0.47, 0.42); + p_config.blue_color = Color(0.44, 0.67, 0.98); + p_config.magenta_color = Color(0.98, 0.44, 0.98); + p_config.cyan_color = Color(0.37, 0.98, 0.98); if (!p_config.dark_theme) { // Darken some colors to be readable on a light background. p_config.success_color = p_config.success_color.lerp(p_config.mono_color, 0.35); p_config.warning_color = Color(0.82, 0.56, 0.1); p_config.error_color = Color(0.8, 0.22, 0.22); + p_config.blue_color = p_config.blue_color.lerp(p_config.mono_color, 0.35); + p_config.magenta_color = p_config.magenta_color.lerp(p_config.mono_color, 0.3); + p_config.cyan_color = p_config.cyan_color.lerp(p_config.mono_color, 0.35); } p_theme->set_color("mono_color", EditorStringName(Editor), p_config.mono_color); @@ -2182,6 +2188,16 @@ void EditorThemeManager::_populate_editor_styles(const Ref &p_theme p_theme->set_color("warning_color", "EditorProperty", p_config.warning_color); p_theme->set_color("readonly_warning_color", "EditorProperty", readonly_warning_color); + // Used to color `print_rich()` usage with basic RichTextLabel colors in the editor log. + // NOTE: These color names are non-semantic. Only use these generic colors if no specific + // color suits your use case (such as `error_color`). + p_theme->set_color("red_color", "Editor", p_config.error_color); + p_theme->set_color("green_color", "Editor", p_config.success_color); + p_theme->set_color("yellow_color", "Editor", p_config.warning_color); + p_theme->set_color("blue_color", "Editor", p_config.blue_color); + p_theme->set_color("magenta_color", "Editor", p_config.magenta_color); + p_theme->set_color("cyan_color", "Editor", p_config.cyan_color); + Ref style_property_group_note = p_config.base_style->duplicate(); Color property_group_note_color = p_config.accent_color; property_group_note_color.a = 0.1; diff --git a/editor/themes/editor_theme_manager.h b/editor/themes/editor_theme_manager.h index ca5e1a4e2d94..003305fda88e 100644 --- a/editor/themes/editor_theme_manager.h +++ b/editor/themes/editor_theme_manager.h @@ -100,6 +100,9 @@ class EditorThemeManager { Color success_color; Color warning_color; Color error_color; + Color blue_color; + Color magenta_color; + Color cyan_color; Color extra_border_color_1; Color extra_border_color_2;