From 4bd25bb92cb49f051d834bc257352493e130fa3a Mon Sep 17 00:00:00 2001 From: Leroy Hopson Date: Mon, 1 Apr 2024 20:08:39 +1300 Subject: [PATCH] feat(theme)!: set a default theme Adds 'Terminal' type to the default theme. Sets values to those similar to CodeEdit and TextEdit. Colors default to Xterm defaults. --- addons/godot_xterm/native/src/constants.cpp | 2 + addons/godot_xterm/native/src/terminal.cpp | 60 ++++++++++++++++----- addons/godot_xterm/native/src/terminal.h | 2 + docs/conf.py | 2 + docs/index.md | 1 + docs/themes.md | 55 +++++++++++++++++++ 6 files changed, 108 insertions(+), 14 deletions(-) create mode 100644 docs/themes.md diff --git a/addons/godot_xterm/native/src/constants.cpp b/addons/godot_xterm/native/src/constants.cpp index a3f4027..fb4702c 100644 --- a/addons/godot_xterm/native/src/constants.cpp +++ b/addons/godot_xterm/native/src/constants.cpp @@ -15,6 +15,8 @@ const char* Terminal::COLOR_NAMES[18] = { "foreground_color", "background_color", }; +// These match the font names of RichTextLabel: https://docs.godotengine.org/en/4.2/classes/class_richtextlabel.html. +// They are all expected to be monospace fonts. const char* Terminal::FONT_TYPES[4] = { "normal_font", "bold_font", "italics_font", "bold_italics_font", }; diff --git a/addons/godot_xterm/native/src/terminal.cpp b/addons/godot_xterm/native/src/terminal.cpp index 4a2c5ec..077cd12 100644 --- a/addons/godot_xterm/native/src/terminal.cpp +++ b/addons/godot_xterm/native/src/terminal.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -87,6 +89,7 @@ void Terminal::_bind_methods() Terminal::Terminal() { + set_default_theme_items(); set_focus_mode(FOCUS_ALL); max_scrollback = 1000; @@ -383,20 +386,6 @@ void Terminal::_get_property_list(List *p_list) const { p_list->push_back(PropertyInfo(Variant::INT, "cols", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY)); p_list->push_back(PropertyInfo(Variant::INT, "rows", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_READ_ONLY)); - - p_list->push_back(PropertyInfo(Variant::NIL, "Theme Overrides", PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP)); - p_list->push_back(PropertyInfo(Variant::NIL, "Colors", PROPERTY_HINT_NONE, "theme_override_colors/", PROPERTY_USAGE_SUBGROUP)); - for (int i = 0; i < TSM_COLOR_NUM; ++i) - { - p_list->push_back(PropertyInfo(Variant::COLOR, "theme_override_colors/" + String(COLOR_NAMES[i]), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE)); - } - p_list->push_back(PropertyInfo(Variant::NIL, "Fonts", PROPERTY_HINT_NONE, "theme_override_fonts/", PROPERTY_USAGE_SUBGROUP)); - for (const String font_type : FONT_TYPES) - { - p_list->push_back(PropertyInfo(Variant::OBJECT, "theme_override_fonts/" + font_type, PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE)); - } - p_list->push_back(PropertyInfo(Variant::NIL, "Font Sizes", PROPERTY_HINT_NONE, "theme_override_font_sizes/", PROPERTY_USAGE_SUBGROUP)); - p_list->push_back(PropertyInfo(Variant::INT, "theme_override_font_sizes/font_size", PROPERTY_HINT_RANGE, "1,256,1,or_greater,suffix:px", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_CHECKABLE)); } bool Terminal::_is_valid_color_name(const String &p_name) @@ -822,3 +811,46 @@ void Terminal::_on_selection_held() { queue_redraw(); selection_timer->start(); } + +// Add default theme items for the "Terminal" theme type if they don't exist. +// These defaults match Godot's built-in default theme (note: this is different from the default editor theme). +void Terminal::set_default_theme_items() { + Ref default_theme = ThemeDB::get_singleton()->get_default_theme(); + if (default_theme->get_type_list().has("Terminal")) return; + + // Default colors and font sizes from CodeEdit, TextEdit, et al. + // A comment on the translucency of the default background color: https://github.com/godotengine/godot/pull/51159#issuecomment-891127783. + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "background_color", "Terminal", Color(0.1, 0.1, 0.1, 0.6)); + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "foreground_color", "Terminal", Color(0.875, 0.875, 0.875, 1)); + default_theme->set_theme_item(Theme::DATA_TYPE_FONT_SIZE, "font_size", "Terminal", 16); + + // Default ANSI colors based on xterm defaults: https://en.wikipedia.org/wiki/ANSI_escape_code#Colors. + // Some discussion about the slight difference of the blue colors: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=241717. + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_0_color" , "Terminal", Color::hex(0x000000FF)); // Black + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_1_color" , "Terminal", Color::hex(0xCD0000FF)); // Red + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_2_color" , "Terminal", Color::hex(0x00CD00FF)); // Green + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_3_color" , "Terminal", Color::hex(0xCDCD00FF)); // Yellow + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_4_color" , "Terminal", Color::hex(0x0000EEFF)); // Blue + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_5_color" , "Terminal", Color::hex(0xCD00CDFF)); // Magenta + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_6_color" , "Terminal", Color::hex(0x00CDCDFF)); // Cyan + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_7_color" , "Terminal", Color::hex(0xE5E5E5FF)); // White + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_8_color" , "Terminal", Color::hex(0x7F7F7FFF)); // Bright Black (Gray) + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_9_color" , "Terminal", Color::hex(0xFF0000FF)); // Bright Red + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_10_color", "Terminal", Color::hex(0x00FF00FF)); // Bright Green + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_11_color", "Terminal", Color::hex(0xFFFF00FF)); // Bright Yellow + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_12_color", "Terminal", Color::hex(0x5C5CFFFF)); // Bright Blue + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_13_color", "Terminal", Color::hex(0xFF00FFFF)); // Bright Magenta + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_14_color", "Terminal", Color::hex(0x00FFFFFF)); // Bright Cyan + default_theme->set_theme_item(Theme::DATA_TYPE_COLOR, "ansi_15_color", "Terminal", Color::hex(0xFFFFFFFF)); // Bright White + + // No monospaced font in the default theme, so try to import our own. Will default to a non-monospace font otherwise. + ResourceLoader* rl = ResourceLoader::get_singleton(); + String const font_path = "res://addons/godot_xterm/themes/fonts/regular.tres"; + if (rl->exists(font_path)) { + Ref default_font = rl->load(font_path); + for (int i = FontType::NORMAL; i <= FontType::BOLD_ITALICS; i++) { + FontType type = static_cast(i); + default_theme->set_theme_item(Theme::DATA_TYPE_FONT, FONT_TYPES[type], "Terminal", default_font); + } + } +} diff --git a/addons/godot_xterm/native/src/terminal.h b/addons/godot_xterm/native/src/terminal.h index 5ee7d34..ae8c06a 100644 --- a/addons/godot_xterm/native/src/terminal.h +++ b/addons/godot_xterm/native/src/terminal.h @@ -177,6 +177,8 @@ namespace godot typedef std::function ScreenCopyFunction; String _copy_screen(ScreenCopyFunction func); + + void set_default_theme_items(); }; } // namespace godot diff --git a/docs/conf.py b/docs/conf.py index 0c43690..ae73e6a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -45,6 +45,7 @@ myst_substitutions = { # Godot classes. 'AudioStream': '[AudioStream](' + godot_class.format('audiostream.html') + ')', 'CanvasItem': '[CanvasItem](' + godot_class.format('canvasitem.html') + ')', + 'CodeEdit': '[CodeEdit](' + godot_class.format('code_edit.html') + ')', 'Color': '[Color](' + godot_class.format('color.html') + ')', 'Control': '[Control](' + godot_class.format('control.html') + ')', 'Error': '[Error](' + godot_class.format('%40globalscope.html#enum-globalscope-error') + ')', @@ -57,6 +58,7 @@ myst_substitutions = { 'PoolByteArray': '[PoolByteArray](' + godot_class.format('poolbytearray.html') + ')', 'PoolStringArray': '[PoolStringArray](' + godot_class.format('poolstringarray.html') + ')', 'String': '[String](' + godot_class.format('string.html') + ')', + 'TextEdit': '[TextEdit](' + godot_class.format('text_edit.html') + ')', 'Vector2': '[Vector2](' + godot_class.format('vector2.html') + ')', 'bool': '[bool](' + godot_class.format('bool.html') + ')', 'float': '[float](' + godot_class.format('float.html') + ')', diff --git a/docs/index.md b/docs/index.md index 7c18661..b9c6a1c 100644 --- a/docs/index.md +++ b/docs/index.md @@ -24,6 +24,7 @@ Primarily developed and tested on Linux, it also supports macOS with partial sup :caption: Table of Contents introduction +themes setup/index api/index CHANGELOG diff --git a/docs/themes.md b/docs/themes.md new file mode 100644 index 0000000..9e8df69 --- /dev/null +++ b/docs/themes.md @@ -0,0 +1,55 @@ +# Themes + +This section explains how you can go about themeing the {{Terminal}} node. + +## Default + +If you add a {{Terminal}} node to your scene without any themes or theme overrides, then the default theme will apply. +This default theme is based on the default theme that Godot uses for the {{TextEdit}} and {{CodeEdit}} nodes. + +### Font + +[JetBrains Mono](https://www.jetbrains.com/lp/mono/) is the default font. +This is the same default font as the Godot code editor (since version 4). +It is not included with the default theme, so we bundle it separately. + +:::{caution} +Only the regular version of the font is included. The **bold**, _italic_, and **_bold italic_** variants are not. +If you want these, you'll need to include them in a custom theme. +::: +:::{error} +This font has support for ligatures (see: [Ligatures for Code](https://github.com/JetBrains/JetBrainsMono?tab=readme-ov-file#ligatures-for-code)). +While the engine supports this feature, GodotXterm currently does not, and there are no immediate plans to support it. +::: + +The default font size is 16. + +### Colors + +GodotXterm uses the same default font color and background color as Godot's {{TextEdit}} and {{CodeEdit}} nodes. + +:::{note} +The default background color of Control nodes is intentionally traslucent. +See [the discussion](https://github.com/godotengine/godot/pull/51159#issuecomment-891126656) on the Godot GitHub repo about this. +::: + +The default ANSI colors are the same as [the xterm defaults](https://en.wikipedia.org/wiki/ANSI_escape_code#Colors). + +| FG | BG | Color Name | Theme Item Name | Hex Code Value | Color Block | +| --- | --- | -------------- | --------------- | -------------- | -------------------------------------- | +| 30 | 40 | Black | ansi_0_color | `#000000` | ██ | +| 31 | 41 | Red | ansi_1_color | `#CD0000` | ██ | +| 32 | 42 | Green | ansi_2_color | `#00CD00` | ██ | +| 33 | 43 | Yellow | ansi_3_color | `#CDCD00` | ██ | +| 34 | 44 | Blue | ansi_4_color | `#0000EE` | ██ | +| 35 | 45 | Magenta | ansi_5_color | `#CD00CD` | ██ | +| 36 | 46 | Cyan | ansi_6_color | `#00CDCD` | ██ | +| 37 | 47 | White | ansi_7_color | `#E5E5E5` | ██ | +| 90 | 100 | Bright Black | ansi_8_color | `#7F7F7F` | ██ | +| 91 | 101 | Bright Red | ansi_9_color | `#FF0000` | ██ | +| 92 | 102 | Bright Green | ansi_10_color | `#00FF00` | ██ | +| 93 | 103 | Bright Yellow | ansi_11_color | `#FFFF00` | ██ | +| 94 | 104 | Bright Blue | ansi_12_color | `#5C5CFF` | ██ | +| 95 | 105 | Bright Magenta | ansi_13_color | `#FF00FF` | ██ | +| 96 | 106 | Bright Cyan | ansi_14_color | `#00FFFF` | ██ | +| 97 | 107 | Bright White | ansi_15_color | `#FFFFFF` | ██ |