summaryrefslogtreecommitdiff
path: root/scene
diff options
context:
space:
mode:
Diffstat (limited to 'scene')
-rw-r--r--scene/2d/collision_object_2d.cpp4
-rw-r--r--scene/2d/collision_object_2d.h4
-rw-r--r--scene/3d/collision_object_3d.cpp2
-rw-r--r--scene/3d/collision_object_3d.h2
-rw-r--r--scene/3d/label_3d.cpp17
-rw-r--r--scene/SCsub1
-rw-r--r--scene/animation/animation_player.cpp2
-rw-r--r--scene/gui/base_button.cpp3
-rw-r--r--scene/gui/color_picker.cpp8
-rw-r--r--scene/gui/control.cpp95
-rw-r--r--scene/gui/control.h4
-rw-r--r--scene/gui/file_dialog.cpp10
-rw-r--r--scene/gui/graph_edit.cpp12
-rw-r--r--scene/gui/label.cpp3
-rw-r--r--scene/gui/menu_bar.cpp15
-rw-r--r--scene/gui/menu_bar.h2
-rw-r--r--scene/gui/menu_button.cpp14
-rw-r--r--scene/gui/option_button.cpp20
-rw-r--r--scene/gui/popup_menu.cpp156
-rw-r--r--scene/gui/rich_text_label.cpp29
-rw-r--r--scene/main/window.cpp15
-rw-r--r--scene/register_scene_types.cpp69
-rw-r--r--scene/register_scene_types.h3
-rw-r--r--scene/resources/animation.cpp134
-rw-r--r--scene/resources/animation_library.cpp2
-rw-r--r--scene/resources/default_theme/default_theme.cpp20
-rw-r--r--scene/resources/default_theme/default_theme.h1
-rw-r--r--scene/resources/font.cpp37
-rw-r--r--scene/resources/material.cpp2
-rw-r--r--scene/resources/packed_scene.cpp47
-rw-r--r--scene/resources/primitive_meshes.cpp17
-rw-r--r--scene/resources/theme.cpp79
-rw-r--r--scene/resources/theme.h29
-rw-r--r--scene/resources/visual_shader_nodes.cpp404
-rw-r--r--scene/resources/visual_shader_nodes.h126
-rw-r--r--scene/theme/SCsub5
-rw-r--r--scene/theme/theme_db.cpp237
-rw-r--r--scene/theme/theme_db.h95
38 files changed, 1265 insertions, 460 deletions
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index 85de1fedee..a79c81e8bd 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -612,6 +612,10 @@ void CollisionObject2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject2D::shape_find_owner);
GDVIRTUAL_BIND(_input_event, "viewport", "event", "shape_idx");
+ GDVIRTUAL_BIND(_mouse_enter);
+ GDVIRTUAL_BIND(_mouse_exit);
+ GDVIRTUAL_BIND(_mouse_shape_enter, "shape_idx");
+ GDVIRTUAL_BIND(_mouse_shape_exit, "shape_idx");
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "viewport", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index af216edc98..48ea59e040 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -103,6 +103,10 @@ protected:
void set_body_mode(PhysicsServer2D::BodyMode p_mode);
GDVIRTUAL3(_input_event, Viewport *, Ref<InputEvent>, int)
+ GDVIRTUAL0(_mouse_enter)
+ GDVIRTUAL0(_mouse_exit)
+ GDVIRTUAL1(_mouse_shape_enter, int)
+ GDVIRTUAL1(_mouse_shape_exit, int)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index 48eb2a66b1..f5e3e8b015 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -469,6 +469,8 @@ void CollisionObject3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("shape_find_owner", "shape_index"), &CollisionObject3D::shape_find_owner);
GDVIRTUAL_BIND(_input_event, "camera", "event", "position", "normal", "shape_idx");
+ GDVIRTUAL_BIND(_mouse_enter);
+ GDVIRTUAL_BIND(_mouse_exit);
ADD_SIGNAL(MethodInfo("input_event", PropertyInfo(Variant::OBJECT, "camera", PROPERTY_HINT_RESOURCE_TYPE, "Node"), PropertyInfo(Variant::OBJECT, "event", PROPERTY_HINT_RESOURCE_TYPE, "InputEvent"), PropertyInfo(Variant::VECTOR3, "position"), PropertyInfo(Variant::VECTOR3, "normal"), PropertyInfo(Variant::INT, "shape_idx")));
ADD_SIGNAL(MethodInfo("mouse_entered"));
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 51c31da79f..c638be9d90 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -113,6 +113,8 @@ protected:
bool is_only_update_transform_changes_enabled() const;
GDVIRTUAL5(_input_event, Camera3D *, Ref<InputEvent>, Vector3, Vector3, int)
+ GDVIRTUAL0(_mouse_enter)
+ GDVIRTUAL0(_mouse_exit)
public:
void set_collision_layer(uint32_t p_layer);
uint32_t get_collision_layer() const;
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index 40b8af7d63..e4a7cf6ee5 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -34,6 +34,7 @@
#include "scene/main/viewport.h"
#include "scene/resources/theme.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
void Label3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_horizontal_alignment", "alignment"), &Label3D::set_horizontal_alignment);
@@ -734,13 +735,13 @@ Ref<Font> Label3D::_get_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
@@ -753,11 +754,11 @@ Ref<Font> Label3D::_get_font_or_default() const {
// Lastly, fall back on the items defined in the default Theme, if they exist.
{
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
@@ -768,7 +769,7 @@ Ref<Font> Label3D::_get_font_or_default() const {
}
// If they don't exist, use any type to return the default/empty value.
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, Callable(const_cast<Label3D *>(this), "_font_changed"));
diff --git a/scene/SCsub b/scene/SCsub
index 92288211bb..b4b2d6dd0a 100644
--- a/scene/SCsub
+++ b/scene/SCsub
@@ -17,6 +17,7 @@ SConscript("animation/SCsub")
SConscript("audio/SCsub")
SConscript("resources/SCsub")
SConscript("debugger/SCsub")
+SConscript("theme/SCsub")
# Build it all as a library
lib = env.add_library("scene", env.scene_sources)
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index 0e2598cbc7..073f61bfdd 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -1501,7 +1501,7 @@ bool AnimationPlayer::has_animation(const StringName &p_name) const {
}
Ref<Animation> AnimationPlayer::get_animation(const StringName &p_name) const {
- ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: %s.", p_name));
+ ERR_FAIL_COND_V_MSG(!animation_set.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
const AnimationData &data = animation_set[p_name];
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 87a7355bb2..cee7c049a9 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -65,8 +65,9 @@ void BaseButton::gui_input(const Ref<InputEvent> &p_event) {
bool button_masked = mouse_button.is_valid() && (mouse_button_to_mask(mouse_button->get_button_index()) & button_mask) != MouseButton::NONE;
if (button_masked || ui_accept) {
was_mouse_pressed = button_masked;
-
on_action_event(p_event);
+ was_mouse_pressed = false;
+
return;
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 9eef45f412..a417e7b9e2 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -536,7 +536,7 @@ void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
btn_preset->set_preset_color(p_color);
btn_preset->set_custom_minimum_size(Size2(p_size, p_size));
btn_preset->connect("gui_input", callable_mp(this, &ColorPicker::_preset_input).bind(p_color));
- btn_preset->set_tooltip(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
+ btn_preset->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
preset_container->add_child(btn_preset);
}
@@ -1236,7 +1236,7 @@ ColorPicker::ColorPicker() :
btn_pick->set_flat(true);
hb_smpl->add_child(btn_pick);
btn_pick->set_toggle_mode(true);
- btn_pick->set_tooltip(RTR("Pick a color from the editor window."));
+ btn_pick->set_tooltip_text(RTR("Pick a color from the editor window."));
btn_pick->connect("pressed", callable_mp(this, &ColorPicker::_screen_pick_pressed));
VBoxContainer *vbl = memnew(VBoxContainer);
@@ -1276,7 +1276,7 @@ ColorPicker::ColorPicker() :
text_type = memnew(Button);
hhb->add_child(text_type);
text_type->set_text("#");
- text_type->set_tooltip(RTR("Switch between hexadecimal and code values."));
+ text_type->set_tooltip_text(RTR("Switch between hexadecimal and code values."));
if (Engine::get_singleton()->is_editor_hint()) {
text_type->connect("pressed", callable_mp(this, &ColorPicker::_text_type_toggled));
} else {
@@ -1337,7 +1337,7 @@ ColorPicker::ColorPicker() :
btn_add_preset = memnew(Button);
btn_add_preset->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- btn_add_preset->set_tooltip(RTR("Add current color as a preset."));
+ btn_add_preset->set_tooltip_text(RTR("Add current color as a preset."));
btn_add_preset->connect("pressed", callable_mp(this, &ColorPicker::_add_preset_pressed));
preset_container->add_child(btn_add_preset);
}
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 9b6a19c50a..4de16a0a29 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -43,6 +43,7 @@
#include "scene/main/canvas_layer.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
#include "servers/text_server.h"
@@ -193,15 +194,15 @@ void Control::get_argument_options(const StringName &p_function, int p_idx, List
List<StringName> sn;
String pf = p_function;
if (pf == "add_theme_color_override" || pf == "has_theme_color" || pf == "has_theme_color_override" || pf == "get_theme_color") {
- Theme::get_default()->get_color_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_color_list(get_class(), &sn);
} else if (pf == "add_theme_style_override" || pf == "has_theme_style" || pf == "has_theme_style_override" || pf == "get_theme_style") {
- Theme::get_default()->get_stylebox_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_stylebox_list(get_class(), &sn);
} else if (pf == "add_theme_font_override" || pf == "has_theme_font" || pf == "has_theme_font_override" || pf == "get_theme_font") {
- Theme::get_default()->get_font_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_list(get_class(), &sn);
} else if (pf == "add_theme_font_size_override" || pf == "has_theme_font_size" || pf == "has_theme_font_size_override" || pf == "get_theme_font_size") {
- Theme::get_default()->get_font_size_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_font_size_list(get_class(), &sn);
} else if (pf == "add_theme_constant_override" || pf == "has_theme_constant" || pf == "has_theme_constant_override" || pf == "get_theme_constant") {
- Theme::get_default()->get_constant_list(get_class(), &sn);
+ ThemeDB::get_singleton()->get_default_theme()->get_constant_list(get_class(), &sn);
}
sn.sort_custom<StringName::AlphCompare>();
@@ -344,7 +345,7 @@ bool Control::_get(const StringName &p_name, Variant &r_ret) const {
}
void Control::_get_property_list(List<PropertyInfo> *p_list) const {
- Ref<Theme> theme = Theme::get_default();
+ Ref<Theme> theme = ThemeDB::get_singleton()->get_default_theme();
p_list->push_back(PropertyInfo(Variant::NIL, TTRC("Theme Overrides"), PROPERTY_HINT_NONE, "theme_override_", PROPERTY_USAGE_GROUP));
@@ -429,9 +430,9 @@ void Control::_validate_property(PropertyInfo &p_property) const {
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
- Theme::get_default()->get_type_variation_list(get_class_name(), &names);
- if (Theme::get_project_default().is_valid()) {
- Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
@@ -2419,22 +2420,22 @@ T Control::get_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_project_default()->get_theme_item(p_data_type, p_name, E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(p_data_type, p_name, E);
}
}
}
// Lastly, fall back on the items defined in the default Theme, if they exist.
for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
- return Theme::get_default()->get_theme_item(p_data_type, p_name, E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, E);
}
}
// If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(p_data_type, p_name, p_theme_types[0]);
}
bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_owner_window, Theme::DataType p_data_type, const StringName &p_name, List<StringName> p_theme_types) {
@@ -2475,9 +2476,9 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
for (const StringName &E : p_theme_types) {
- if (Theme::get_project_default()->has_theme_item(p_data_type, p_name, E)) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(p_data_type, p_name, E)) {
return true;
}
}
@@ -2485,7 +2486,7 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
// Lastly, fall back on the items defined in the default Theme, if they exist.
for (const StringName &E : p_theme_types) {
- if (Theme::get_default()->has_theme_item(p_data_type, p_name, E)) {
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(p_data_type, p_name, E)) {
return true;
}
}
@@ -2494,13 +2495,13 @@ bool Control::has_theme_item_in_types(Control *p_theme_owner, Window *p_theme_ow
void Control::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == data.theme_type_variation) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(data.theme_type_variation) != StringName()) {
- Theme::get_project_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(data.theme_type_variation) != StringName()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
} else {
- Theme::get_default()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), data.theme_type_variation, p_list);
}
} else {
- Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
}
}
@@ -2851,17 +2852,17 @@ float Control::fetch_theme_default_base_scale(Control *p_theme_owner, Window *p_
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_base_scale()) {
- return Theme::get_project_default()->get_default_base_scale();
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_base_scale();
}
}
// Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_base_scale()) {
- return Theme::get_default()->get_default_base_scale();
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_base_scale()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_base_scale();
}
- return Theme::get_fallback_base_scale();
+ return ThemeDB::get_singleton()->get_fallback_base_scale();
}
float Control::get_theme_default_base_scale() const {
@@ -2902,17 +2903,17 @@ Ref<Font> Control::fetch_theme_default_font(Control *p_theme_owner, Window *p_th
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font()) {
- return Theme::get_project_default()->get_default_font();
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_font();
}
}
// Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font()) {
- return Theme::get_default()->get_default_font();
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_font()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font();
}
- return Theme::get_fallback_font();
+ return ThemeDB::get_singleton()->get_fallback_font();
}
Ref<Font> Control::get_theme_default_font() const {
@@ -2953,17 +2954,17 @@ int Control::fetch_theme_default_font_size(Control *p_theme_owner, Window *p_the
}
// Secondly, check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
- if (Theme::get_project_default()->has_default_font_size()) {
- return Theme::get_project_default()->get_default_font_size();
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_default_font_size();
}
}
// Lastly, fall back on the default Theme.
- if (Theme::get_default()->has_default_font_size()) {
- return Theme::get_default()->get_default_font_size();
+ if (ThemeDB::get_singleton()->get_default_theme()->has_default_font_size()) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_default_font_size();
}
- return Theme::get_fallback_font_size();
+ return ThemeDB::get_singleton()->get_fallback_font_size();
}
int Control::get_theme_default_font_size() const {
@@ -3062,12 +3063,12 @@ bool Control::is_auto_translating() const {
// Extra properties.
-void Control::set_tooltip(const String &p_tooltip) {
- data.tooltip = p_tooltip;
+void Control::set_tooltip_text(const String &p_hint) {
+ data.tooltip = p_hint;
update_configuration_warnings();
}
-String Control::_get_tooltip() const {
+String Control::get_tooltip_text() const {
return data.tooltip;
}
@@ -3383,9 +3384,9 @@ void Control::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_v_grow_direction", "direction"), &Control::set_v_grow_direction);
ClassDB::bind_method(D_METHOD("get_v_grow_direction"), &Control::get_v_grow_direction);
- ClassDB::bind_method(D_METHOD("set_tooltip", "tooltip"), &Control::set_tooltip);
+ ClassDB::bind_method(D_METHOD("set_tooltip_text", "hint"), &Control::set_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_tooltip_text"), &Control::get_tooltip_text);
ClassDB::bind_method(D_METHOD("get_tooltip", "at_position"), &Control::get_tooltip, DEFVAL(Point2()));
- ClassDB::bind_method(D_METHOD("_get_tooltip"), &Control::_get_tooltip);
ClassDB::bind_method(D_METHOD("set_default_cursor_shape", "shape"), &Control::set_default_cursor_shape);
ClassDB::bind_method(D_METHOD("get_default_cursor_shape"), &Control::get_default_cursor_shape);
@@ -3475,8 +3476,8 @@ void Control::_bind_methods() {
ADD_GROUP("Auto Translate", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "auto_translate"), "set_auto_translate", "is_auto_translating");
- ADD_GROUP("Hint", "hint_");
- ADD_PROPERTY(PropertyInfo(Variant::STRING, "hint_tooltip", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip", "_get_tooltip");
+ ADD_GROUP("Tooltip", "tooltip_");
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "tooltip_text", PROPERTY_HINT_MULTILINE_TEXT), "set_tooltip_text", "get_tooltip_text");
ADD_GROUP("Focus", "focus_");
ADD_PROPERTYI(PropertyInfo(Variant::NODE_PATH, "focus_neighbor_left", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Control"), "set_focus_neighbor", "get_focus_neighbor", SIDE_LEFT);
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 82d3d8d24a..6215594ae0 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -312,7 +312,7 @@ private:
// Extra properties.
- String _get_tooltip() const;
+ String get_tooltip_text() const;
protected:
// Dynamic properties.
@@ -604,7 +604,7 @@ public:
// Extra properties.
- void set_tooltip(const String &p_tooltip);
+ void set_tooltip_text(const String &text);
virtual String get_tooltip(const Point2 &p_pos) const;
virtual Control *make_custom_tooltip(const String &p_text) const;
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index 7965b12edd..57655afb4c 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -1015,13 +1015,13 @@ FileDialog::FileDialog() {
dir_prev = memnew(Button);
dir_prev->set_flat(true);
- dir_prev->set_tooltip(RTR("Go to previous folder."));
+ dir_prev->set_tooltip_text(RTR("Go to previous folder."));
dir_next = memnew(Button);
dir_next->set_flat(true);
- dir_next->set_tooltip(RTR("Go to next folder."));
+ dir_next->set_tooltip_text(RTR("Go to next folder."));
dir_up = memnew(Button);
dir_up->set_flat(true);
- dir_up->set_tooltip(RTR("Go to parent folder."));
+ dir_up->set_tooltip_text(RTR("Go to parent folder."));
hbc->add_child(dir_prev);
hbc->add_child(dir_next);
hbc->add_child(dir_up);
@@ -1045,7 +1045,7 @@ FileDialog::FileDialog() {
refresh = memnew(Button);
refresh->set_flat(true);
- refresh->set_tooltip(RTR("Refresh files."));
+ refresh->set_tooltip_text(RTR("Refresh files."));
refresh->connect("pressed", callable_mp(this, &FileDialog::update_file_list));
hbc->add_child(refresh);
@@ -1053,7 +1053,7 @@ FileDialog::FileDialog() {
show_hidden->set_flat(true);
show_hidden->set_toggle_mode(true);
show_hidden->set_pressed(is_showing_hidden_files());
- show_hidden->set_tooltip(RTR("Toggle the visibility of hidden files."));
+ show_hidden->set_tooltip_text(RTR("Toggle the visibility of hidden files."));
show_hidden->connect("toggled", callable_mp(this, &FileDialog::set_show_hidden_files));
hbc->add_child(show_hidden);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index a4c2236706..00f2e48601 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -2496,28 +2496,28 @@ GraphEdit::GraphEdit() {
zoom_minus = memnew(Button);
zoom_minus->set_flat(true);
zoom_hb->add_child(zoom_minus);
- zoom_minus->set_tooltip(RTR("Zoom Out"));
+ zoom_minus->set_tooltip_text(RTR("Zoom Out"));
zoom_minus->connect("pressed", callable_mp(this, &GraphEdit::_zoom_minus));
zoom_minus->set_focus_mode(FOCUS_NONE);
zoom_reset = memnew(Button);
zoom_reset->set_flat(true);
zoom_hb->add_child(zoom_reset);
- zoom_reset->set_tooltip(RTR("Zoom Reset"));
+ zoom_reset->set_tooltip_text(RTR("Zoom Reset"));
zoom_reset->connect("pressed", callable_mp(this, &GraphEdit::_zoom_reset));
zoom_reset->set_focus_mode(FOCUS_NONE);
zoom_plus = memnew(Button);
zoom_plus->set_flat(true);
zoom_hb->add_child(zoom_plus);
- zoom_plus->set_tooltip(RTR("Zoom In"));
+ zoom_plus->set_tooltip_text(RTR("Zoom In"));
zoom_plus->connect("pressed", callable_mp(this, &GraphEdit::_zoom_plus));
zoom_plus->set_focus_mode(FOCUS_NONE);
snap_button = memnew(Button);
snap_button->set_flat(true);
snap_button->set_toggle_mode(true);
- snap_button->set_tooltip(RTR("Enable snap and show grid."));
+ snap_button->set_tooltip_text(RTR("Enable snap and show grid."));
snap_button->connect("pressed", callable_mp(this, &GraphEdit::_snap_toggled));
snap_button->set_pressed(true);
snap_button->set_focus_mode(FOCUS_NONE);
@@ -2534,7 +2534,7 @@ GraphEdit::GraphEdit() {
minimap_button = memnew(Button);
minimap_button->set_flat(true);
minimap_button->set_toggle_mode(true);
- minimap_button->set_tooltip(RTR("Enable grid minimap."));
+ minimap_button->set_tooltip_text(RTR("Enable grid minimap."));
minimap_button->connect("pressed", callable_mp(this, &GraphEdit::_minimap_toggled));
minimap_button->set_pressed(true);
minimap_button->set_focus_mode(FOCUS_NONE);
@@ -2543,7 +2543,7 @@ GraphEdit::GraphEdit() {
layout_button = memnew(Button);
layout_button->set_flat(true);
zoom_hb->add_child(layout_button);
- layout_button->set_tooltip(RTR("Arrange nodes."));
+ layout_button->set_tooltip_text(RTR("Arrange nodes."));
layout_button->connect("pressed", callable_mp(this, &GraphEdit::arrange_nodes));
layout_button->set_focus_mode(FOCUS_NONE);
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index b15578f222..fa7d4195cb 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -908,9 +908,10 @@ void Label::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "is_clipping_text");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "uppercase"), "set_uppercase", "is_uppercase");
+
+ ADD_GROUP("Displayed Text", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "lines_skipped", PROPERTY_HINT_RANGE, "0,999,1"), "set_lines_skipped", "get_lines_skipped");
ADD_PROPERTY(PropertyInfo(Variant::INT, "max_lines_visible", PROPERTY_HINT_RANGE, "-1,999,1"), "set_max_lines_visible", "get_max_lines_visible");
-
// Note: "visible_characters" and "visible_ratio" should be set after "text" to be correctly applied.
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 9eba2feaf7..9b7b67d83e 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -60,7 +60,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
if (active_menu >= 0) {
get_menu_popup(active_menu)->hide();
}
- _open_popup(selected_menu);
+ _open_popup(selected_menu, true);
}
return;
} else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
@@ -82,7 +82,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
if (active_menu >= 0) {
get_menu_popup(active_menu)->hide();
}
- _open_popup(selected_menu);
+ _open_popup(selected_menu, true);
}
return;
}
@@ -110,7 +110,7 @@ void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
-void MenuBar::_open_popup(int p_index) {
+void MenuBar::_open_popup(int p_index, bool p_focus_item) {
ERR_FAIL_INDEX(p_index, menu_cache.size());
PopupMenu *pm = get_menu_popup(p_index);
@@ -134,6 +134,15 @@ void MenuBar::_open_popup(int p_index) {
pm->set_parent_rect(Rect2(Point2(screen_pos - pm->get_position()), Size2(screen_size.x, screen_pos.y)));
pm->popup();
+ if (p_focus_item) {
+ for (int i = 0; i < pm->get_item_count(); i++) {
+ if (!pm->is_item_disabled(i)) {
+ pm->set_current_index(i);
+ break;
+ }
+ }
+ }
+
update();
}
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
index 3c4a25fd06..b7d9933ab2 100644
--- a/scene/gui/menu_bar.h
+++ b/scene/gui/menu_bar.h
@@ -84,7 +84,7 @@ class MenuBar : public Control {
Vector<PopupMenu *> _get_popups() const;
int get_menu_idx_from_control(PopupMenu *p_child) const;
- void _open_popup(int p_index);
+ void _open_popup(int p_index, bool p_focus_item = false);
void _popup_visibility_changed(bool p_visible);
void _update_submenu(const String &p_menu_name, PopupMenu *p_child);
void _clear_menu();
diff --git a/scene/gui/menu_button.cpp b/scene/gui/menu_button.cpp
index e6e17cc881..f779f87ae7 100644
--- a/scene/gui/menu_button.cpp
+++ b/scene/gui/menu_button.cpp
@@ -103,9 +103,14 @@ void MenuButton::pressed() {
popup->set_position(gp);
popup->set_parent_rect(Rect2(Point2(gp - popup->get_position()), size));
- // If not triggered by the mouse, start the popup with its first item selected.
- if (popup->get_item_count() > 0 && !_was_pressed_by_mouse()) {
- popup->set_current_index(0);
+ // If not triggered by the mouse, start the popup with its first enabled item focused.
+ if (!_was_pressed_by_mouse()) {
+ for (int i = 0; i < popup->get_item_count(); i++) {
+ if (!popup->is_item_disabled(i)) {
+ popup->set_current_index(i);
+ break;
+ }
+ }
}
popup->popup();
@@ -161,7 +166,10 @@ void MenuButton::_notification(int p_what) {
if (menu_btn_other && menu_btn_other != this && menu_btn_other->is_switch_on_hover() && !menu_btn_other->is_disabled() &&
(get_parent()->is_ancestor_of(menu_btn_other) || menu_btn_other->get_parent()->is_ancestor_of(popup))) {
popup->hide();
+
menu_btn_other->pressed();
+ // As the popup wasn't triggered by a mouse click, the item focus needs to be removed manually.
+ menu_btn_other->get_popup()->set_current_index(-1);
}
} break;
}
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index 881acdbf3a..a87c46e8ac 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -207,12 +207,24 @@ void OptionButton::pressed() {
popup->set_position(get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
popup->set_size(Size2(size.width, 0));
- // If not triggered by the mouse, start the popup with the checked item selected.
- if (popup->get_item_count() > 0) {
+ // If not triggered by the mouse, start the popup with the checked item (or the first enabled one) focused.
+ if (current != NONE_SELECTED && !popup->is_item_disabled(current)) {
if (!_was_pressed_by_mouse()) {
- popup->set_current_index(current > -1 ? current : 0);
+ popup->set_current_index(current);
} else {
- popup->scroll_to_item(current > -1 ? current : 0);
+ popup->scroll_to_item(current);
+ }
+ } else {
+ for (int i = 0; i < popup->get_item_count(); i++) {
+ if (!popup->is_item_disabled(i)) {
+ if (!_was_pressed_by_mouse()) {
+ popup->set_current_index(i);
+ } else {
+ popup->scroll_to_item(i);
+ }
+
+ break;
+ }
}
}
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 4e2aec0278..c8bb9fd530 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -216,9 +216,14 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
submenu_pum->activated_by_keyboard = p_by_keyboard;
- // If not triggered by the mouse, start the popup with its first item selected.
- if (submenu_pum->get_item_count() > 0 && p_by_keyboard) {
- submenu_pum->set_current_index(0);
+ // If not triggered by the mouse, start the popup with its first enabled item focused.
+ if (p_by_keyboard) {
+ for (int i = 0; i < submenu_pum->get_item_count(); i++) {
+ if (!submenu_pum->is_item_disabled(i)) {
+ submenu_pum->set_current_index(i);
+ break;
+ }
+ }
}
submenu_pum->popup();
@@ -278,102 +283,104 @@ void PopupMenu::_submenu_timeout() {
void PopupMenu::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (p_event->is_action("ui_down") && p_event->is_pressed()) {
- int search_from = mouse_over + 1;
- if (search_from >= items.size()) {
- search_from = 0;
- }
-
- bool match_found = false;
- for (int i = search_from; i < items.size(); i++) {
- if (!items[i].separator && !items[i].disabled) {
- mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
- scroll_to_item(i);
- control->update();
- set_input_as_handled();
- match_found = true;
- break;
+ if (!items.is_empty()) {
+ if (p_event->is_action("ui_down") && p_event->is_pressed()) {
+ int search_from = mouse_over + 1;
+ if (search_from >= items.size()) {
+ search_from = 0;
}
- }
- if (!match_found) {
- // If the last item is not selectable, try re-searching from the start.
- for (int i = 0; i < search_from; i++) {
+ bool match_found = false;
+ for (int i = search_from; i < items.size(); i++) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal(SNAME("id_focused"), i);
scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
- }
- } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
- int search_from = mouse_over - 1;
- if (search_from < 0) {
- search_from = items.size() - 1;
- }
- bool match_found = false;
- for (int i = search_from; i >= 0; i--) {
- if (!items[i].separator && !items[i].disabled) {
- mouse_over = i;
- emit_signal(SNAME("id_focused"), i);
- scroll_to_item(i);
- control->update();
- set_input_as_handled();
- match_found = true;
- break;
+ if (!match_found) {
+ // If the last item is not selectable, try re-searching from the start.
+ for (int i = 0; i < search_from; i++) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal(SNAME("id_focused"), i);
+ scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
+ }
+ } else if (p_event->is_action("ui_up") && p_event->is_pressed()) {
+ int search_from = mouse_over - 1;
+ if (search_from < 0) {
+ search_from = items.size() - 1;
}
- }
- if (!match_found) {
- // If the first item is not selectable, try re-searching from the end.
- for (int i = items.size() - 1; i >= search_from; i--) {
+ bool match_found = false;
+ for (int i = search_from; i >= 0; i--) {
if (!items[i].separator && !items[i].disabled) {
mouse_over = i;
emit_signal(SNAME("id_focused"), i);
scroll_to_item(i);
control->update();
set_input_as_handled();
+ match_found = true;
break;
}
}
- }
- } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
- Node *n = get_parent();
- if (n) {
- if (Object::cast_to<PopupMenu>(n)) {
- hide();
- set_input_as_handled();
- } else if (Object::cast_to<MenuBar>(n)) {
- Object::cast_to<MenuBar>(n)->gui_input(p_event);
- set_input_as_handled();
- return;
+
+ if (!match_found) {
+ // If the first item is not selectable, try re-searching from the end.
+ for (int i = items.size() - 1; i >= search_from; i--) {
+ if (!items[i].separator && !items[i].disabled) {
+ mouse_over = i;
+ emit_signal(SNAME("id_focused"), i);
+ scroll_to_item(i);
+ control->update();
+ set_input_as_handled();
+ break;
+ }
+ }
}
- }
- } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
- if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
- _activate_submenu(mouse_over, true);
- set_input_as_handled();
- } else {
+ } else if (p_event->is_action("ui_left") && p_event->is_pressed()) {
Node *n = get_parent();
- if (n && Object::cast_to<MenuBar>(n)) {
- Object::cast_to<MenuBar>(n)->gui_input(p_event);
- set_input_as_handled();
- return;
+ if (n) {
+ if (Object::cast_to<PopupMenu>(n)) {
+ hide();
+ set_input_as_handled();
+ } else if (Object::cast_to<MenuBar>(n)) {
+ Object::cast_to<MenuBar>(n)->gui_input(p_event);
+ set_input_as_handled();
+ return;
+ }
}
- }
- } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
- if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
- if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
+ } else if (p_event->is_action("ui_right") && p_event->is_pressed()) {
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator && !items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
_activate_submenu(mouse_over, true);
+ set_input_as_handled();
} else {
- activate_item(mouse_over);
+ Node *n = get_parent();
+ if (n && Object::cast_to<MenuBar>(n)) {
+ Object::cast_to<MenuBar>(n)->gui_input(p_event);
+ set_input_as_handled();
+ return;
+ }
+ }
+ } else if (p_event->is_action("ui_accept") && p_event->is_pressed()) {
+ if (mouse_over >= 0 && mouse_over < items.size() && !items[mouse_over].separator) {
+ if (!items[mouse_over].submenu.is_empty() && submenu_over != mouse_over) {
+ _activate_submenu(mouse_over, true);
+ } else {
+ activate_item(mouse_over);
+ }
+ set_input_as_handled();
}
- set_input_as_handled();
}
}
@@ -1532,14 +1539,19 @@ bool PopupMenu::is_item_shortcut_disabled(int p_idx) const {
}
void PopupMenu::set_current_index(int p_idx) {
- ERR_FAIL_INDEX(p_idx, items.size());
+ if (p_idx != -1) {
+ ERR_FAIL_INDEX(p_idx, items.size());
+ }
if (mouse_over == p_idx) {
return;
}
mouse_over = p_idx;
- scroll_to_item(mouse_over);
+ if (mouse_over != -1) {
+ scroll_to_item(mouse_over);
+ }
+
control->update();
}
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 3f1f16cd51..8ce8663091 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -5172,31 +5172,36 @@ void RichTextLabel::_bind_methods() {
// Note: set "bbcode_enabled" first, to avoid unnecessary "text" resets.
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "bbcode_enabled"), "set_use_bbcode", "is_using_bbcode");
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "threaded"), "set_threaded", "is_threaded");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "progress_bar_delay", PROPERTY_HINT_NONE, "suffix:ms"), "set_progress_bar_delay", "get_progress_bar_delay");
-
- ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT), "set_text", "get_text");
+
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fit_content_height"), "set_fit_content_height", "is_fit_content_height_enabled");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_active"), "set_scroll_active", "is_scroll_active");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_following"), "set_scroll_follow", "is_scroll_following");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_size", PROPERTY_HINT_RANGE, "0,24,1"), "set_tab_size", "get_tab_size");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
+
+ ADD_GROUP("Markup", "");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "custom_effects", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "RichTextEffect"), (PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE)), "set_effects", "get_effects");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "meta_underlined"), "set_meta_underline", "is_meta_underlined");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hint_underlined"), "set_hint_underline", "is_hint_underlined");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode");
+ ADD_GROUP("Threading", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "threaded"), "set_threaded", "is_threaded");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "progress_bar_delay", PROPERTY_HINT_NONE, "suffix:ms"), "set_progress_bar_delay", "get_progress_bar_delay");
+
+ ADD_GROUP("Text Selection", "");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selection_enabled"), "set_selection_enabled", "is_selection_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_selected_font_color"), "set_override_selected_font_color", "is_overriding_selected_font_color");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled");
+
+ ADD_GROUP("Displayed Text", "");
// Note: "visible_characters" and "visible_ratio" should be set after "text" to be correctly applied.
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters", PROPERTY_HINT_RANGE, "-1,128000,1"), "set_visible_characters", "get_visible_characters");
ADD_PROPERTY(PropertyInfo(Variant::INT, "visible_characters_behavior", PROPERTY_HINT_ENUM, "Characters Before Shaping,Characters After Shaping,Glyphs (Layout Direction),Glyphs (Left-to-Right),Glyphs (Right-to-Left)"), "set_visible_characters_behavior", "get_visible_characters_behavior");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "visible_ratio", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_visible_ratio", "get_visible_ratio");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled");
-
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index 1b7aa787e7..5328ae7b8c 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -35,6 +35,7 @@
#include "core/string/translation.h"
#include "scene/gui/control.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
void Window::set_title(const String &p_title) {
title = p_title;
@@ -1330,13 +1331,13 @@ StringName Window::get_theme_type_variation() const {
void Window::_get_theme_type_dependencies(const StringName &p_theme_type, List<StringName> *p_list) const {
if (p_theme_type == StringName() || p_theme_type == get_class_name() || p_theme_type == theme_type_variation) {
- if (Theme::get_project_default().is_valid() && Theme::get_project_default()->get_type_variation_base(theme_type_variation) != StringName()) {
- Theme::get_project_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid() && ThemeDB::get_singleton()->get_project_theme()->get_type_variation_base(theme_type_variation) != StringName()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
} else {
- Theme::get_default()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), theme_type_variation, p_list);
}
} else {
- Theme::get_default()->get_type_dependencies(p_theme_type, StringName(), p_list);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(p_theme_type, StringName(), p_list);
}
}
@@ -1522,9 +1523,9 @@ void Window::_validate_property(PropertyInfo &p_property) const {
// Only the default theme and the project theme are used for the list of options.
// This is an imposed limitation to simplify the logic needed to leverage those options.
- Theme::get_default()->get_type_variation_list(get_class_name(), &names);
- if (Theme::get_project_default().is_valid()) {
- Theme::get_project_default()->get_type_variation_list(get_class_name(), &names);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_variation_list(get_class_name(), &names);
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
+ ThemeDB::get_singleton()->get_project_theme()->get_type_variation_list(get_class_name(), &names);
}
names.sort_custom<StringName::AlphCompare>();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 8b43f778e5..6c7bc552bf 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -193,12 +193,14 @@
#include "scene/resources/sky.h"
#include "scene/resources/sky_material.h"
#include "scene/resources/sphere_shape_3d.h"
+#include "scene/resources/style_box.h"
#include "scene/resources/surface_tool.h"
#include "scene/resources/syntax_highlighter.h"
#include "scene/resources/text_file.h"
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
#include "scene/resources/texture.h"
+#include "scene/resources/theme.h"
#include "scene/resources/tile_set.h"
#include "scene/resources/video_stream.h"
#include "scene/resources/visual_shader.h"
@@ -210,6 +212,7 @@
#include "scene/resources/world_boundary_shape_2d.h"
#include "scene/resources/world_boundary_shape_3d.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
#include "scene/main/shader_globals_override.h"
@@ -611,6 +614,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeColorFunc);
GDREGISTER_CLASS(VisualShaderNodeTransformFunc);
GDREGISTER_CLASS(VisualShaderNodeUVFunc);
+ GDREGISTER_CLASS(VisualShaderNodeUVPolarCoord);
GDREGISTER_CLASS(VisualShaderNodeDotProduct);
GDREGISTER_CLASS(VisualShaderNodeVectorLen);
GDREGISTER_CLASS(VisualShaderNodeDeterminant);
@@ -649,6 +653,7 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeTexture2DArrayUniform);
GDREGISTER_CLASS(VisualShaderNodeTexture3DUniform);
GDREGISTER_CLASS(VisualShaderNodeCubemapUniform);
+ GDREGISTER_CLASS(VisualShaderNodeLinearSceneDepth);
GDREGISTER_CLASS(VisualShaderNodeIf);
GDREGISTER_CLASS(VisualShaderNodeSwitch);
GDREGISTER_CLASS(VisualShaderNodeFresnel);
@@ -658,6 +663,10 @@ void register_scene_types() {
GDREGISTER_CLASS(VisualShaderNodeCompare);
GDREGISTER_CLASS(VisualShaderNodeMultiplyAdd);
GDREGISTER_CLASS(VisualShaderNodeBillboard);
+ GDREGISTER_CLASS(VisualShaderNodeDistanceFade);
+ GDREGISTER_CLASS(VisualShaderNodeProximityFade);
+ GDREGISTER_CLASS(VisualShaderNodeRandomRange);
+ GDREGISTER_CLASS(VisualShaderNodeRemap);
GDREGISTER_ABSTRACT_CLASS(VisualShaderNodeVarying);
GDREGISTER_CLASS(VisualShaderNodeVaryingSetter);
GDREGISTER_CLASS(VisualShaderNodeVaryingGetter);
@@ -1124,62 +1133,8 @@ void register_scene_types() {
SceneDebugger::initialize();
}
-void initialize_theme() {
- // Allow creating the default theme at a different scale to suit higher/lower base resolutions.
- float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- String theme_path = GLOBAL_DEF_RST("gui/theme/custom", "");
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", "");
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
-
- const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false);
- const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false);
-
- GLOBAL_DEF_RST("gui/theme/lcd_subpixel_layout", 1);
- ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/lcd_subpixel_layout", PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR"));
- ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false);
-
- Ref<Font> font;
- if (!font_path.is_empty()) {
- font = ResourceLoader::load(font_path);
- if (!font.is_valid()) {
- ERR_PRINT("Error loading custom font '" + font_path + "'");
- }
- }
-
- // Always make the default theme to avoid invalid default font/icon/style in the given theme.
- if (RenderingServer::get_singleton()) {
- make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps);
- }
-
- if (!theme_path.is_empty()) {
- Ref<Theme> theme = ResourceLoader::load(theme_path);
- if (theme.is_valid()) {
- Theme::set_project_default(theme);
- if (font.is_valid()) {
- Theme::set_fallback_font(font);
- }
- } else {
- ERR_PRINT("Error loading custom theme '" + theme_path + "'");
- }
- }
-}
-
void unregister_scene_types() {
SceneDebugger::deinitialize();
- clear_default_theme();
ResourceLoader::remove_resource_format_loader(resource_loader_texture_layered);
resource_loader_texture_layered.unref();
@@ -1221,3 +1176,9 @@ void unregister_scene_types() {
ColorPicker::finish_shaders();
SceneStringNames::free();
}
+
+void register_scene_singletons() {
+ GDREGISTER_CLASS(ThemeDB);
+
+ Engine::get_singleton()->add_singleton(Engine::Singleton("ThemeDB", ThemeDB::get_singleton()));
+}
diff --git a/scene/register_scene_types.h b/scene/register_scene_types.h
index dce8713976..cb3249c5d7 100644
--- a/scene/register_scene_types.h
+++ b/scene/register_scene_types.h
@@ -33,7 +33,6 @@
void register_scene_types();
void unregister_scene_types();
-
-void initialize_theme();
+void register_scene_singletons();
#endif // REGISTER_SCENE_TYPES_H
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index 823617328e..9d5bc18c96 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -4201,25 +4201,25 @@ void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_er
void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D);
- RotationTrack *tt = static_cast<RotationTrack *>(tracks[p_idx]);
+ RotationTrack *rt = static_cast<RotationTrack *>(tracks[p_idx]);
int i = 0;
- while (i < tt->rotations.size() - 2) {
- TKey<Quaternion> t0 = tt->rotations[i];
- TKey<Quaternion> t1 = tt->rotations[i + 1];
- TKey<Quaternion> t2 = tt->rotations[i + 2];
+ while (i < rt->rotations.size() - 2) {
+ TKey<Quaternion> t0 = rt->rotations[i];
+ TKey<Quaternion> t1 = rt->rotations[i + 1];
+ TKey<Quaternion> t2 = rt->rotations[i + 2];
bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- tt->rotations.remove_at(i + 1);
+ rt->rotations.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->rotations.size() == 2) {
- if ((tt->rotations[0].value - tt->rotations[1].value).length() < p_allowed_precision_error) {
- tt->rotations.remove_at(1);
+ if (rt->rotations.size() == 2) {
+ if ((rt->rotations[0].value - rt->rotations[1].value).length() < p_allowed_precision_error) {
+ rt->rotations.remove_at(1);
}
}
}
@@ -4227,25 +4227,25 @@ void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_er
void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_SCALE_3D);
- ScaleTrack *tt = static_cast<ScaleTrack *>(tracks[p_idx]);
+ ScaleTrack *st = static_cast<ScaleTrack *>(tracks[p_idx]);
int i = 0;
- while (i < tt->scales.size() - 2) {
- TKey<Vector3> t0 = tt->scales[i];
- TKey<Vector3> t1 = tt->scales[i + 1];
- TKey<Vector3> t2 = tt->scales[i + 2];
+ while (i < st->scales.size() - 2) {
+ TKey<Vector3> t0 = st->scales[i];
+ TKey<Vector3> t1 = st->scales[i + 1];
+ TKey<Vector3> t2 = st->scales[i + 2];
bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
if (erase) {
- tt->scales.remove_at(i + 1);
+ st->scales.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->scales.size() == 2) {
- if ((tt->scales[0].value - tt->scales[1].value).length() < p_allowed_precision_error) {
- tt->scales.remove_at(1);
+ if (st->scales.size() == 2) {
+ if ((st->scales[0].value - st->scales[1].value).length() < p_allowed_precision_error) {
+ st->scales.remove_at(1);
}
}
}
@@ -4253,25 +4253,25 @@ void Animation::_scale_track_optimize(int p_idx, real_t p_allowed_velocity_err,
void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_BLEND_SHAPE);
- BlendShapeTrack *tt = static_cast<BlendShapeTrack *>(tracks[p_idx]);
+ BlendShapeTrack *bst = static_cast<BlendShapeTrack *>(tracks[p_idx]);
int i = 0;
- while (i < tt->blend_shapes.size() - 2) {
- TKey<float> t0 = tt->blend_shapes[i];
- TKey<float> t1 = tt->blend_shapes[i + 1];
- TKey<float> t2 = tt->blend_shapes[i + 2];
+ while (i < bst->blend_shapes.size() - 2) {
+ TKey<float> t0 = bst->blend_shapes[i];
+ TKey<float> t1 = bst->blend_shapes[i + 1];
+ TKey<float> t2 = bst->blend_shapes[i + 2];
bool erase = _float_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_precision_error);
if (erase) {
- tt->blend_shapes.remove_at(i + 1);
+ bst->blend_shapes.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->blend_shapes.size() == 2) {
- if (abs(tt->blend_shapes[0].value - tt->blend_shapes[1].value) < p_allowed_precision_error) {
- tt->blend_shapes.remove_at(1);
+ if (bst->blend_shapes.size() == 2) {
+ if (abs(bst->blend_shapes[0].value - bst->blend_shapes[1].value) < p_allowed_precision_error) {
+ bst->blend_shapes.remove_at(1);
}
}
}
@@ -4279,28 +4279,28 @@ void Animation::_blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity
void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
ERR_FAIL_INDEX(p_idx, tracks.size());
ERR_FAIL_COND(tracks[p_idx]->type != TYPE_VALUE);
- ValueTrack *tt = static_cast<ValueTrack *>(tracks[p_idx]);
- if (tt->values.size() == 0) {
+ ValueTrack *vt = static_cast<ValueTrack *>(tracks[p_idx]);
+ if (vt->values.size() == 0) {
return;
}
- Variant::Type type = tt->values[0].value.get_type();
+ Variant::Type type = vt->values[0].value.get_type();
// Special case for angle interpolation.
- bool is_using_angle = tt->interpolation == Animation::INTERPOLATION_LINEAR_ANGLE || tt->interpolation == Animation::INTERPOLATION_CUBIC_ANGLE;
+ bool is_using_angle = vt->interpolation == Animation::INTERPOLATION_LINEAR_ANGLE || vt->interpolation == Animation::INTERPOLATION_CUBIC_ANGLE;
int i = 0;
- while (i < tt->values.size() - 2) {
+ while (i < vt->values.size() - 2) {
bool erase = false;
switch (type) {
case Variant::FLOAT: {
TKey<float> t0;
TKey<float> t1;
TKey<float> t2;
- t0.time = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
if (is_using_angle) {
float diff1 = fmod(t1.value - t0.value, Math_TAU);
t1.value = t0.value + fmod(2.0 * diff1, Math_TAU) - diff1;
@@ -4316,36 +4316,36 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err,
TKey<Vector2> t0;
TKey<Vector2> t1;
TKey<Vector2> t2;
- t0.time = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
erase = _vector2_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
} break;
case Variant::VECTOR3: {
TKey<Vector3> t0;
TKey<Vector3> t1;
TKey<Vector3> t2;
- t0.time = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
} break;
case Variant::QUATERNION: {
TKey<Quaternion> t0;
TKey<Quaternion> t1;
TKey<Quaternion> t2;
- t0.time = tt->values[i].time;
- t1.time = tt->values[i + 1].time;
- t2.time = tt->values[i + 2].time;
- t0.value = tt->values[i].value;
- t1.value = tt->values[i + 1].value;
- t2.value = tt->values[i + 2].value;
+ t0.time = vt->values[i].time;
+ t1.time = vt->values[i + 1].time;
+ t2.time = vt->values[i + 2].time;
+ t0.value = vt->values[i].value;
+ t1.value = vt->values[i + 1].value;
+ t2.value = vt->values[i + 2].value;
erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error);
} break;
default: {
@@ -4353,18 +4353,18 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err,
}
if (erase) {
- tt->values.remove_at(i + 1);
+ vt->values.remove_at(i + 1);
} else {
i++;
}
}
- if (tt->values.size() == 2) {
+ if (vt->values.size() == 2) {
bool single_key = false;
switch (type) {
case Variant::FLOAT: {
- float val_0 = tt->values[0].value;
- float val_1 = tt->values[1].value;
+ float val_0 = vt->values[0].value;
+ float val_1 = vt->values[1].value;
if (is_using_angle) {
float diff1 = fmod(val_1 - val_0, Math_TAU);
val_1 = val_0 + fmod(2.0 * diff1, Math_TAU) - diff1;
@@ -4372,25 +4372,25 @@ void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err,
single_key = abs(val_0 - val_1) < p_allowed_precision_error;
} break;
case Variant::VECTOR2: {
- Vector2 val_0 = tt->values[0].value;
- Vector2 val_1 = tt->values[1].value;
+ Vector2 val_0 = vt->values[0].value;
+ Vector2 val_1 = vt->values[1].value;
single_key = (val_0 - val_1).length() < p_allowed_precision_error;
} break;
case Variant::VECTOR3: {
- Vector3 val_0 = tt->values[0].value;
- Vector3 val_1 = tt->values[1].value;
+ Vector3 val_0 = vt->values[0].value;
+ Vector3 val_1 = vt->values[1].value;
single_key = (val_0 - val_1).length() < p_allowed_precision_error;
} break;
case Variant::QUATERNION: {
- Quaternion val_0 = tt->values[0].value;
- Quaternion val_1 = tt->values[1].value;
+ Quaternion val_0 = vt->values[0].value;
+ Quaternion val_1 = vt->values[1].value;
single_key = (val_0 - val_1).length() < p_allowed_precision_error;
} break;
default: {
} break;
}
if (single_key) {
- tt->values.remove_at(1);
+ vt->values.remove_at(1);
}
}
}
diff --git a/scene/resources/animation_library.cpp b/scene/resources/animation_library.cpp
index 5f725b2fbe..427d418551 100644
--- a/scene/resources/animation_library.cpp
+++ b/scene/resources/animation_library.cpp
@@ -85,7 +85,7 @@ bool AnimationLibrary::has_animation(const StringName &p_name) const {
}
Ref<Animation> AnimationLibrary::get_animation(const StringName &p_name) const {
- ERR_FAIL_COND_V(!animations.has(p_name), Ref<Animation>());
+ ERR_FAIL_COND_V_MSG(!animations.has(p_name), Ref<Animation>(), vformat("Animation not found: \"%s\".", p_name));
return animations[p_name];
}
diff --git a/scene/resources/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index 5bfa1adfe5..410f35e597 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -35,6 +35,7 @@
#include "default_theme_icons.gen.h"
#include "scene/resources/font.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/text_server.h"
#include "modules/modules_enabled.gen.h" // For svg.
@@ -1101,18 +1102,11 @@ void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPos
fill_default_theme(t, default_font, bold_font, bold_italics_font, italics_font, default_icon, default_style, default_scale);
- Theme::set_default(t);
- Theme::set_fallback_base_scale(default_scale);
- Theme::set_fallback_icon(default_icon);
- Theme::set_fallback_style(default_style);
- Theme::set_fallback_font(default_font);
- Theme::set_fallback_font_size(default_font_size * default_scale);
-}
+ ThemeDB::get_singleton()->set_default_theme(t);
-void clear_default_theme() {
- Theme::set_project_default(nullptr);
- Theme::set_default(nullptr);
- Theme::set_fallback_icon(nullptr);
- Theme::set_fallback_style(nullptr);
- Theme::set_fallback_font(nullptr);
+ ThemeDB::get_singleton()->set_fallback_base_scale(default_scale);
+ ThemeDB::get_singleton()->set_fallback_icon(default_icon);
+ ThemeDB::get_singleton()->set_fallback_stylebox(default_style);
+ ThemeDB::get_singleton()->set_fallback_font(default_font);
+ ThemeDB::get_singleton()->set_fallback_font_size(default_font_size * default_scale);
}
diff --git a/scene/resources/default_theme/default_theme.h b/scene/resources/default_theme/default_theme.h
index 15be5e676f..003934ce90 100644
--- a/scene/resources/default_theme/default_theme.h
+++ b/scene/resources/default_theme/default_theme.h
@@ -37,6 +37,5 @@ const int default_font_size = 16;
void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const Ref<Font> &bold_font, const Ref<Font> &bold_italics_font, const Ref<Font> &italics_font, Ref<Texture2D> &default_icon, Ref<StyleBox> &default_style, float p_scale);
void make_default_theme(float p_scale, Ref<Font> p_font, TextServer::SubpixelPositioning p_font_subpixel = TextServer::SUBPIXEL_POSITIONING_AUTO, TextServer::Hinting p_font_hinting = TextServer::HINTING_LIGHT, TextServer::FontAntialiasing p_font_antialiased = TextServer::FONT_ANTIALIASING_GRAY, bool p_font_msdf = false, bool p_font_generate_mipmaps = false);
-void clear_default_theme();
#endif // DEFAULT_THEME_H
diff --git a/scene/resources/font.cpp b/scene/resources/font.cpp
index be57d9c965..8ec5678f0a 100644
--- a/scene/resources/font.cpp
+++ b/scene/resources/font.cpp
@@ -39,6 +39,7 @@
#include "scene/resources/text_line.h"
#include "scene/resources/text_paragraph.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
/*************************************************************************/
/* Font */
@@ -2552,13 +2553,13 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2569,13 +2570,13 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
// Lastly, fall back on the items defined in the default Theme, if they exist.
- if (Theme::get_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_default_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2585,7 +2586,7 @@ Ref<Font> FontVariation::_get_base_font_or_default() const {
}
// If they don't exist, use any type to return the default/empty value.
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<FontVariation *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2859,13 +2860,13 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2876,13 +2877,13 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
// Lastly, fall back on the items defined in the default Theme, if they exist.
- if (Theme::get_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_default_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
@@ -2892,7 +2893,7 @@ Ref<Font> SystemFont::_get_base_font_or_default() const {
}
// If they don't exist, use any type to return the default/empty value.
- Ref<Font> f = Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ Ref<Font> f = ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
if (f.is_valid()) {
theme_font = f;
theme_font->connect(CoreStringNames::get_singleton()->changed, callable_mp(reinterpret_cast<Font *>(const_cast<SystemFont *>(this)), &Font::_invalidate_rids), CONNECT_REFERENCE_COUNTED);
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index bd0e470112..32ddef1693 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -2971,6 +2971,8 @@ BaseMaterial3D::BaseMaterial3D(bool p_orm) :
set_transparency(TRANSPARENCY_DISABLED);
set_alpha_antialiasing(ALPHA_ANTIALIASING_OFF);
+ // Alpha scissor threshold of 0.5 matches the glTF specification and Label3D default.
+ // <https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#_material_alphacutoff>
set_alpha_scissor_threshold(0.5);
set_alpha_hash_scale(1.0);
set_alpha_antialiasing_edge(0.3);
diff --git a/scene/resources/packed_scene.cpp b/scene/resources/packed_scene.cpp
index 0e1b18d584..33334801c3 100644
--- a/scene/resources/packed_scene.cpp
+++ b/scene/resources/packed_scene.cpp
@@ -279,25 +279,36 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
Ref<Resource> res = value;
if (res.is_valid()) {
if (res->is_local_to_scene()) {
- HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
-
- if (E) {
- value = E->value;
+ // In a situation where a local-to-scene resource is used in a child node of a non-editable instance,
+ // we need to avoid the parent scene from overriding the resource potentially also used in the root
+ // of the instantiated scene. That would to the instance having two different instances of the resource.
+ // Since at this point it's too late to propagate the resource instance in the parent scene to all the relevant
+ // nodes in the instance (and that would require very complex bookkepping), what we do instead is
+ // tampering the resource object already there with the values from the node in the parent scene and
+ // then tell this node to reference that resource.
+ if (n.instance >= 0) {
+ Ref<Resource> node_res = node->get(snames[nprops[j].name]);
+ if (node_res.is_valid()) {
+ node_res->copy_from(res);
+ node_res->configure_for_local_scene(node, resources_local_to_scene);
+ value = node_res;
+ }
} else {
+ HashMap<Ref<Resource>, Ref<Resource>>::Iterator E = resources_local_to_scene.find(res);
Node *base = i == 0 ? node : ret_nodes[0];
-
- if (p_edit_state == GEN_EDIT_STATE_MAIN || p_edit_state == GEN_EDIT_STATE_MAIN_INHERITED) {
- //for the main scene, use the resource as is
- res->configure_for_local_scene(base, resources_local_to_scene);
- resources_local_to_scene[res] = res;
-
+ if (E) {
+ value = E->value;
} else {
- //for instances, a copy must be made
- Node *base2 = i == 0 ? node : ret_nodes[0];
- Ref<Resource> local_dupe = res->duplicate_for_local_scene(base2, resources_local_to_scene);
- resources_local_to_scene[res] = local_dupe;
- res = local_dupe;
- value = local_dupe;
+ if (p_edit_state == GEN_EDIT_STATE_MAIN) {
+ //for the main scene, use the resource as is
+ res->configure_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = res;
+ } else {
+ //for instances, a copy must be made
+ Ref<Resource> local_dupe = res->duplicate_for_local_scene(base, resources_local_to_scene);
+ resources_local_to_scene[res] = local_dupe;
+ value = local_dupe;
+ }
}
}
//must make a copy, because this res is local to scene
@@ -398,7 +409,9 @@ Node *SceneState::instantiate(GenEditState p_edit_state) const {
}
for (KeyValue<Ref<Resource>, Ref<Resource>> &E : resources_local_to_scene) {
- E.value->setup_local_to_scene();
+ if (E.value->get_local_scene() == ret_nodes[0]) {
+ E.value->setup_local_to_scene();
+ }
}
//do connections
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index e993936350..fc5cf2a028 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -32,6 +32,7 @@
#include "core/core_string_names.h"
#include "scene/resources/theme.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
#include "thirdparty/misc/clipper.hpp"
#include "thirdparty/misc/polypartition.h"
@@ -2984,13 +2985,13 @@ Ref<Font> TextMesh::_get_font_or_default() const {
}
// Check the project-defined Theme resource.
- if (Theme::get_project_default().is_valid()) {
+ if (ThemeDB::get_singleton()->get_project_theme().is_valid()) {
List<StringName> theme_types;
- Theme::get_project_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_project_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_project_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- return Theme::get_project_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_project_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return ThemeDB::get_singleton()->get_project_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
}
}
}
@@ -2998,17 +2999,17 @@ Ref<Font> TextMesh::_get_font_or_default() const {
// Lastly, fall back on the items defined in the default Theme, if they exist.
{
List<StringName> theme_types;
- Theme::get_default()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
+ ThemeDB::get_singleton()->get_default_theme()->get_type_dependencies(get_class_name(), StringName(), &theme_types);
for (const StringName &E : theme_types) {
- if (Theme::get_default()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
- return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
+ if (ThemeDB::get_singleton()->get_default_theme()->has_theme_item(Theme::DATA_TYPE_FONT, "font", E)) {
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", E);
}
}
}
// If they don't exist, use any type to return the default/empty value.
- return Theme::get_default()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
+ return ThemeDB::get_singleton()->get_default_theme()->get_theme_item(Theme::DATA_TYPE_FONT, "font", StringName());
}
void TextMesh::set_font_size(int p_size) {
diff --git a/scene/resources/theme.cpp b/scene/resources/theme.cpp
index 3f6eec8497..3321392821 100644
--- a/scene/resources/theme.cpp
+++ b/scene/resources/theme.cpp
@@ -31,17 +31,7 @@
#include "theme.h"
#include "core/string/print_string.h"
-
-// Universal Theme resources used when no other theme has the item.
-Ref<Theme> Theme::default_theme;
-Ref<Theme> Theme::project_default_theme;
-
-// Universal default values, final fallback for every theme.
-float Theme::fallback_base_scale = 1.0;
-Ref<Texture2D> Theme::fallback_icon;
-Ref<StyleBox> Theme::fallback_style;
-Ref<Font> Theme::fallback_font;
-int Theme::fallback_font_size = 16;
+#include "scene/theme/theme_db.h"
// Dynamic properties.
bool Theme::_set(const StringName &p_name, const Variant &p_value) {
@@ -185,64 +175,7 @@ void Theme::_get_property_list(List<PropertyInfo> *p_list) const {
}
}
-// Universal fallback Theme resources.
-Ref<Theme> Theme::get_default() {
- return default_theme;
-}
-
-void Theme::set_default(const Ref<Theme> &p_default) {
- default_theme = p_default;
-}
-
-Ref<Theme> Theme::get_project_default() {
- return project_default_theme;
-}
-
-void Theme::set_project_default(const Ref<Theme> &p_project_default) {
- project_default_theme = p_project_default;
-}
-
-// Universal fallback values for theme item types.
-void Theme::set_fallback_base_scale(float p_base_scale) {
- fallback_base_scale = p_base_scale;
-}
-
-void Theme::set_fallback_icon(const Ref<Texture2D> &p_icon) {
- fallback_icon = p_icon;
-}
-
-void Theme::set_fallback_style(const Ref<StyleBox> &p_style) {
- fallback_style = p_style;
-}
-
-void Theme::set_fallback_font(const Ref<Font> &p_font) {
- fallback_font = p_font;
-}
-
-void Theme::set_fallback_font_size(int p_font_size) {
- fallback_font_size = p_font_size;
-}
-
-float Theme::get_fallback_base_scale() {
- return fallback_base_scale;
-}
-
-Ref<Texture2D> Theme::get_fallback_icon() {
- return fallback_icon;
-}
-
-Ref<StyleBox> Theme::get_fallback_style() {
- return fallback_style;
-}
-
-Ref<Font> Theme::get_fallback_font() {
- return fallback_font;
-}
-
-int Theme::get_fallback_font_size() {
- return fallback_font_size;
-}
-
+// Static helpers.
bool Theme::is_valid_type_name(const String &p_name) {
for (int i = 0; i < p_name.length(); i++) {
if (!is_ascii_identifier_char(p_name[i])) {
@@ -351,7 +284,7 @@ Ref<Texture2D> Theme::get_icon(const StringName &p_name, const StringName &p_the
if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
return icon_map[p_theme_type][p_name];
} else {
- return fallback_icon;
+ return ThemeDB::get_singleton()->get_fallback_icon();
}
}
@@ -461,7 +394,7 @@ Ref<StyleBox> Theme::get_stylebox(const StringName &p_name, const StringName &p_
if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
return style_map[p_theme_type][p_name];
} else {
- return fallback_style;
+ return ThemeDB::get_singleton()->get_fallback_stylebox();
}
}
@@ -573,7 +506,7 @@ Ref<Font> Theme::get_font(const StringName &p_name, const StringName &p_theme_ty
} else if (has_default_font()) {
return default_font;
} else {
- return fallback_font;
+ return ThemeDB::get_singleton()->get_fallback_font();
}
}
@@ -676,7 +609,7 @@ int Theme::get_font_size(const StringName &p_name, const StringName &p_theme_typ
} else if (has_default_font_size()) {
return default_font_size;
} else {
- return fallback_font_size;
+ return ThemeDB::get_singleton()->get_fallback_font_size();
}
}
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index a2aca5e61f..ed1dc7c938 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -102,17 +102,6 @@ protected:
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
- // Universal Theme resources used when no other theme has the item.
- static Ref<Theme> default_theme;
- static Ref<Theme> project_default_theme;
-
- // Universal default values, final fallback for every theme.
- static float fallback_base_scale;
- static Ref<Texture2D> fallback_icon;
- static Ref<StyleBox> fallback_style;
- static Ref<Font> fallback_font;
- static int fallback_font_size;
-
// Default values configurable for each individual theme.
float default_base_scale = 0.0;
Ref<Font> default_font;
@@ -126,24 +115,6 @@ protected:
virtual void reset_state() override;
public:
- static Ref<Theme> get_default();
- static void set_default(const Ref<Theme> &p_default);
-
- static Ref<Theme> get_project_default();
- static void set_project_default(const Ref<Theme> &p_project_default);
-
- static void set_fallback_base_scale(float p_base_scale);
- static void set_fallback_icon(const Ref<Texture2D> &p_icon);
- static void set_fallback_style(const Ref<StyleBox> &p_style);
- static void set_fallback_font(const Ref<Font> &p_font);
- static void set_fallback_font_size(int p_font_size);
-
- static float get_fallback_base_scale();
- static Ref<Texture2D> get_fallback_icon();
- static Ref<StyleBox> get_fallback_style();
- static Ref<Font> get_fallback_font();
- static int get_fallback_font_size();
-
static bool is_valid_type_name(const String &p_name);
static bool is_valid_item_name(const String &p_name);
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 2911d726b4..3b2b58516d 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -1606,6 +1606,51 @@ VisualShaderNodeCubemap::VisualShaderNodeCubemap() {
simple_decl = false;
}
+////////////// Linear Depth
+
+String VisualShaderNodeLinearSceneDepth::get_caption() const {
+ return "LinearSceneDepth";
+}
+
+int VisualShaderNodeLinearSceneDepth::get_input_port_count() const {
+ return 0;
+}
+
+VisualShaderNodeLinearSceneDepth::PortType VisualShaderNodeLinearSceneDepth::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeLinearSceneDepth::get_input_port_name(int p_port) const {
+ return "";
+}
+
+int VisualShaderNodeLinearSceneDepth::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeLinearSceneDepth::PortType VisualShaderNodeLinearSceneDepth::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeLinearSceneDepth::get_output_port_name(int p_port) const {
+ return "linear depth";
+}
+
+String VisualShaderNodeLinearSceneDepth::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += " float _log_depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;\n";
+ code += " vec3 _depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, _log_depth);\n";
+ code += " vec4 _depth_view = INV_PROJECTION_MATRIX * vec4(_depth_ndc, 1.0);\n";
+ code += " _depth_view.xyz /= _depth_view.w;";
+ code += vformat(" %s = -_depth_view.z;", p_output_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeLinearSceneDepth::VisualShaderNodeLinearSceneDepth() {
+}
+
////////////// Float Op
String VisualShaderNodeFloatOp::get_caption() const {
@@ -3090,6 +3135,107 @@ VisualShaderNodeUVFunc::VisualShaderNodeUVFunc() {
set_input_port_default_value(2, Vector2()); // offset
}
+////////////// UV PolarCoord
+
+String VisualShaderNodeUVPolarCoord::get_caption() const {
+ return "UVPolarCoord";
+}
+
+int VisualShaderNodeUVPolarCoord::get_input_port_count() const {
+ return 4;
+}
+
+VisualShaderNodeUVPolarCoord::PortType VisualShaderNodeUVPolarCoord::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_2D; // uv
+ case 1:
+ return PORT_TYPE_VECTOR_2D; // center
+ case 2:
+ return PORT_TYPE_SCALAR; // zoom
+ case 3:
+ return PORT_TYPE_SCALAR; // repeat
+ default:
+ break;
+ }
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeUVPolarCoord::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "uv";
+ case 1:
+ return "scale";
+ case 2:
+ return "zoom strength";
+ case 3:
+ return "repeat";
+ default:
+ break;
+ }
+ return "";
+}
+
+bool VisualShaderNodeUVPolarCoord::is_input_port_default(int p_port, Shader::Mode p_mode) const {
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ if (p_port == 0) {
+ return true;
+ }
+ }
+ return false;
+}
+
+int VisualShaderNodeUVPolarCoord::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeUVPolarCoord::PortType VisualShaderNodeUVPolarCoord::get_output_port_type(int p_port) const {
+ return PORT_TYPE_VECTOR_2D;
+}
+
+String VisualShaderNodeUVPolarCoord::get_output_port_name(int p_port) const {
+ return "uv";
+}
+
+String VisualShaderNodeUVPolarCoord::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String uv;
+ if (p_input_vars[0].is_empty()) {
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ uv = "UV";
+ } else {
+ uv = "vec2(0.0)";
+ }
+ } else {
+ uv = vformat("%s", p_input_vars[0]);
+ }
+ String center = vformat("%s", p_input_vars[1]);
+ String zoom = vformat("%s", p_input_vars[2]);
+ String repeat = vformat("%s", p_input_vars[3]);
+
+ if (p_mode == Shader::MODE_CANVAS_ITEM) {
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
+ code += vformat(" %s = mod(vec2(__radius * %s, __angle * %s), 1.0);\n", p_output_vars[0], zoom, repeat);
+ } else {
+ code += vformat(" vec2 __dir = %s - %s;\n", uv, center);
+ code += " float __radius = length(__dir) * 2.0;\n";
+ code += " float __angle = atan(__dir.y, __dir.x) * 1.0/(PI * 2.0);\n";
+ code += vformat(" %s = vec2(__radius * %s, __angle * %s);\n", p_output_vars[0], zoom, repeat);
+ }
+
+ return code;
+}
+
+VisualShaderNodeUVPolarCoord::VisualShaderNodeUVPolarCoord() {
+ set_input_port_default_value(1, Vector2(0.5, 0.5)); // center
+ set_input_port_default_value(2, 1.0); // zoom
+ set_input_port_default_value(3, 1.0); // repeat
+}
+
////////////// Dot Product
String VisualShaderNodeDotProduct::get_caption() const {
@@ -7010,3 +7156,261 @@ void VisualShaderNodeBillboard::_bind_methods() {
VisualShaderNodeBillboard::VisualShaderNodeBillboard() {
simple_decl = false;
}
+
+////////////// DistanceFade
+
+String VisualShaderNodeDistanceFade::get_caption() const {
+ return "DistanceFade";
+}
+
+int VisualShaderNodeDistanceFade::get_input_port_count() const {
+ return 2;
+}
+
+VisualShaderNodeDistanceFade::PortType VisualShaderNodeDistanceFade::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SCALAR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDistanceFade::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "min";
+ case 1:
+ return "max";
+ }
+
+ return "";
+}
+
+int VisualShaderNodeDistanceFade::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeDistanceFade::PortType VisualShaderNodeDistanceFade::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeDistanceFade::get_output_port_name(int p_port) const {
+ return "amount";
+}
+
+String VisualShaderNodeDistanceFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+ code += vformat(" %s = clamp(smoothstep(%s, %s,-VERTEX.z),0.0,1.0);\n", p_output_vars[0], p_input_vars[0], p_input_vars[1]);
+ return code;
+}
+
+VisualShaderNodeDistanceFade::VisualShaderNodeDistanceFade() {
+ set_input_port_default_value(0, 0.0);
+ set_input_port_default_value(1, 10.0);
+}
+
+////////////// ProximityFade
+
+String VisualShaderNodeProximityFade::get_caption() const {
+ return "ProximityFade";
+}
+
+int VisualShaderNodeProximityFade::get_input_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeProximityFade::PortType VisualShaderNodeProximityFade::get_input_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeProximityFade::get_input_port_name(int p_port) const {
+ return "distance";
+}
+
+int VisualShaderNodeProximityFade::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeProximityFade::PortType VisualShaderNodeProximityFade::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeProximityFade::get_output_port_name(int p_port) const {
+ return "fade";
+}
+
+String VisualShaderNodeProximityFade::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ String proximity_fade_distance = vformat("%s", p_input_vars[0]);
+ code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
+ code += " __depth_world_pos.xyz /= __depth_world_pos.z;\n";
+ code += vformat(" %s = clamp(1.0 - smoothstep(__depth_world_pos.z + %s, __depth_world_pos.z, VERTEX.z), 0.0, 1.0);\n", p_output_vars[0], p_input_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeProximityFade::VisualShaderNodeProximityFade() {
+ set_input_port_default_value(0, 1.0);
+}
+
+////////////// Random Range
+
+String VisualShaderNodeRandomRange::get_caption() const {
+ return "RandomRange";
+}
+
+int VisualShaderNodeRandomRange::get_input_port_count() const {
+ return 3;
+}
+
+VisualShaderNodeRandomRange::PortType VisualShaderNodeRandomRange::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_VECTOR_3D;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SCALAR;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRandomRange::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "seed";
+ case 1:
+ return "min";
+ case 2:
+ return "max";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRandomRange::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeRandomRange::PortType VisualShaderNodeRandomRange::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRandomRange::get_output_port_name(int p_port) const {
+ return "value";
+}
+
+String VisualShaderNodeRandomRange::generate_global_per_node(Shader::Mode p_mode, int p_id) const {
+ String code;
+
+ code += "\n\n";
+ code += "// 3D Noise with friendly permission by Inigo Quilez\n";
+ code += "vec3 hash_noise_range( vec3 p ) {\n";
+ code += " p *= mat3(vec3(127.1, 311.7, -53.7), vec3(269.5, 183.3, 77.1), vec3(-301.7, 27.3, 215.3));\n";
+ code += " return 2.0 * fract(fract(p)*4375.55) -1.;\n";
+ code += "}\n";
+ code += "\n";
+
+ return code;
+}
+
+String VisualShaderNodeRandomRange::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += vformat(" %s = mix(%s, %s, hash_noise_range(%s).x);\n", p_output_vars[0], p_input_vars[1], p_input_vars[2], p_input_vars[0]);
+
+ return code;
+}
+
+VisualShaderNodeRandomRange::VisualShaderNodeRandomRange() {
+ set_input_port_default_value(0, Vector3(1.0, 1.0, 1.0));
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+}
+
+////////////// Remap
+
+String VisualShaderNodeRemap::get_caption() const {
+ return "Remap";
+}
+
+int VisualShaderNodeRemap::get_input_port_count() const {
+ return 5;
+}
+
+VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_input_port_type(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return PORT_TYPE_SCALAR;
+ case 1:
+ return PORT_TYPE_SCALAR;
+ case 2:
+ return PORT_TYPE_SCALAR;
+ case 3:
+ return PORT_TYPE_SCALAR;
+ case 4:
+ return PORT_TYPE_SCALAR;
+ default:
+ break;
+ }
+
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRemap::get_input_port_name(int p_port) const {
+ switch (p_port) {
+ case 0:
+ return "value";
+ case 1:
+ return "input min";
+ case 2:
+ return "input max";
+ case 3:
+ return "output min";
+ case 4:
+ return "output max";
+ default:
+ break;
+ }
+
+ return "";
+}
+
+int VisualShaderNodeRemap::get_output_port_count() const {
+ return 1;
+}
+
+VisualShaderNodeRemap::PortType VisualShaderNodeRemap::get_output_port_type(int p_port) const {
+ return PORT_TYPE_SCALAR;
+}
+
+String VisualShaderNodeRemap::get_output_port_name(int p_port) const {
+ return "value";
+}
+
+String VisualShaderNodeRemap::generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview) const {
+ String code;
+
+ code += vformat(" float _input_range = %s - %s;\n", p_input_vars[2], p_input_vars[1]);
+ code += vformat(" float _output_range = %s - %s;\n", p_input_vars[4], p_input_vars[3]);
+ code += vformat(" %s = %s + _output_range * ((%s - %s) / _input_range);\n", p_output_vars[0], p_input_vars[3], p_input_vars[0], p_input_vars[1]);
+
+ return code;
+}
+
+VisualShaderNodeRemap::VisualShaderNodeRemap() {
+ set_input_port_default_value(1, 0.0);
+ set_input_port_default_value(2, 1.0);
+ set_input_port_default_value(3, 0.0);
+ set_input_port_default_value(4, 1.0);
+}
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index ffcb41072d..c603a10eae 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -622,6 +622,27 @@ VARIANT_ENUM_CAST(VisualShaderNodeCubemap::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeCubemap::Source)
///////////////////////////////////////
+
+class VisualShaderNodeLinearSceneDepth : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeLinearSceneDepth, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeLinearSceneDepth();
+};
+
+///////////////////////////////////////
/// OPS
///////////////////////////////////////
@@ -1231,6 +1252,30 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeUVFunc::Function)
///////////////////////////////////////
+/// UV POLARCOORD
+///////////////////////////////////////
+
+class VisualShaderNodeUVPolarCoord : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeUVPolarCoord, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+ virtual bool is_input_port_default(int p_port, Shader::Mode p_mode) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeUVPolarCoord();
+};
+
+///////////////////////////////////////
/// DOT
///////////////////////////////////////
@@ -2574,4 +2619,85 @@ public:
VARIANT_ENUM_CAST(VisualShaderNodeBillboard::BillboardType)
+///////////////////////////////////////
+/// DistanceFade
+///////////////////////////////////////
+
+class VisualShaderNodeDistanceFade : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeDistanceFade, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeDistanceFade();
+};
+
+class VisualShaderNodeProximityFade : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeProximityFade, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeProximityFade();
+};
+
+class VisualShaderNodeRandomRange : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRandomRange, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_global_per_node(Shader::Mode p_mode, int p_id) const override;
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRandomRange();
+};
+
+class VisualShaderNodeRemap : public VisualShaderNode {
+ GDCLASS(VisualShaderNodeRemap, VisualShaderNode);
+
+public:
+ virtual String get_caption() const override;
+
+ virtual int get_input_port_count() const override;
+ virtual PortType get_input_port_type(int p_port) const override;
+ virtual String get_input_port_name(int p_port) const override;
+
+ virtual int get_output_port_count() const override;
+ virtual PortType get_output_port_type(int p_port) const override;
+ virtual String get_output_port_name(int p_port) const override;
+
+ virtual String generate_code(Shader::Mode p_mode, VisualShader::Type p_type, int p_id, const String *p_input_vars, const String *p_output_vars, bool p_for_preview = false) const override;
+
+ VisualShaderNodeRemap();
+};
+
#endif // VISUAL_SHADER_NODES_H
diff --git a/scene/theme/SCsub b/scene/theme/SCsub
new file mode 100644
index 0000000000..fc61250247
--- /dev/null
+++ b/scene/theme/SCsub
@@ -0,0 +1,5 @@
+#!/usr/bin/env python
+
+Import("env")
+
+env.add_source_files(env.scene_sources, "*.cpp")
diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp
new file mode 100644
index 0000000000..d6e892cd93
--- /dev/null
+++ b/scene/theme/theme_db.cpp
@@ -0,0 +1,237 @@
+/*************************************************************************/
+/* theme_db.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "theme_db.h"
+
+#include "core/config/project_settings.h"
+#include "core/io/resource_loader.h"
+#include "scene/resources/default_theme/default_theme.h"
+#include "scene/resources/font.h"
+#include "scene/resources/style_box.h"
+#include "scene/resources/texture.h"
+#include "scene/resources/theme.h"
+#include "servers/text_server.h"
+
+// Default engine theme creation and configuration.
+void ThemeDB::initialize_theme() {
+ // Allow creating the default theme at a different scale to suit higher/lower base resolutions.
+ float default_theme_scale = GLOBAL_DEF("gui/theme/default_theme_scale", 1.0);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_theme_scale", PropertyInfo(Variant::FLOAT, "gui/theme/default_theme_scale", PROPERTY_HINT_RANGE, "0.5,8,0.01", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ String theme_path = GLOBAL_DEF_RST("gui/theme/custom", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom", PropertyInfo(Variant::STRING, "gui/theme/custom", PROPERTY_HINT_FILE, "*.tres,*.res,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ String font_path = GLOBAL_DEF_RST("gui/theme/custom_font", "");
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/custom_font", PropertyInfo(Variant::STRING, "gui/theme/custom_font", PROPERTY_HINT_FILE, "*.tres,*.res", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ TextServer::FontAntialiasing font_antialiasing = (TextServer::FontAntialiasing)(int)GLOBAL_DEF_RST("gui/theme/default_font_antialiasing", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_antialiasing", PropertyInfo(Variant::INT, "gui/theme/default_font_antialiasing", PROPERTY_HINT_ENUM, "None,Grayscale,LCD sub-pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ TextServer::Hinting font_hinting = (TextServer::Hinting)(int)GLOBAL_DEF_RST("gui/theme/default_font_hinting", TextServer::HINTING_LIGHT);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_hinting", PropertyInfo(Variant::INT, "gui/theme/default_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ TextServer::SubpixelPositioning font_subpixel_positioning = (TextServer::SubpixelPositioning)(int)GLOBAL_DEF_RST("gui/theme/default_font_subpixel_positioning", TextServer::SUBPIXEL_POSITIONING_AUTO);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/default_font_subpixel_positioning", PropertyInfo(Variant::INT, "gui/theme/default_font_subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One half of a pixel,One quarter of a pixel", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED));
+
+ const bool font_msdf = GLOBAL_DEF_RST("gui/theme/default_font_multichannel_signed_distance_field", false);
+ const bool font_generate_mipmaps = GLOBAL_DEF_RST("gui/theme/default_font_generate_mipmaps", false);
+
+ GLOBAL_DEF_RST("gui/theme/lcd_subpixel_layout", 1);
+ ProjectSettings::get_singleton()->set_custom_property_info("gui/theme/lcd_subpixel_layout", PropertyInfo(Variant::INT, "gui/theme/lcd_subpixel_layout", PROPERTY_HINT_ENUM, "Disabled,Horizontal RGB,Horizontal BGR,Vertical RGB,Vertical BGR"));
+ ProjectSettings::get_singleton()->set_restart_if_changed("gui/theme/lcd_subpixel_layout", false);
+
+ Ref<Font> font;
+ if (!font_path.is_empty()) {
+ font = ResourceLoader::load(font_path);
+ if (!font.is_valid()) {
+ ERR_PRINT("Error loading custom font '" + font_path + "'");
+ }
+ }
+
+ // Always make the default theme to avoid invalid default font/icon/style in the given theme.
+ if (RenderingServer::get_singleton()) {
+ make_default_theme(default_theme_scale, font, font_subpixel_positioning, font_hinting, font_antialiasing, font_msdf, font_generate_mipmaps);
+ }
+
+ if (!theme_path.is_empty()) {
+ Ref<Theme> theme = ResourceLoader::load(theme_path);
+ if (theme.is_valid()) {
+ set_project_theme(theme);
+ if (font.is_valid()) {
+ set_fallback_font(font);
+ }
+ } else {
+ ERR_PRINT("Error loading custom theme '" + theme_path + "'");
+ }
+ }
+}
+
+void ThemeDB::initialize_theme_noproject() {
+ if (RenderingServer::get_singleton()) {
+ make_default_theme(1.0, Ref<Font>());
+ }
+}
+
+// Universal fallback Theme resources.
+
+void ThemeDB::set_default_theme(const Ref<Theme> &p_default) {
+ default_theme = p_default;
+}
+
+Ref<Theme> ThemeDB::get_default_theme() {
+ return default_theme;
+}
+
+void ThemeDB::set_project_theme(const Ref<Theme> &p_project_default) {
+ project_theme = p_project_default;
+}
+
+Ref<Theme> ThemeDB::get_project_theme() {
+ return project_theme;
+}
+
+// Universal fallback values for theme item types.
+
+void ThemeDB::set_fallback_base_scale(float p_base_scale) {
+ if (fallback_base_scale == p_base_scale) {
+ return;
+ }
+
+ fallback_base_scale = p_base_scale;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+float ThemeDB::get_fallback_base_scale() {
+ return fallback_base_scale;
+}
+
+void ThemeDB::set_fallback_font(const Ref<Font> &p_font) {
+ if (fallback_font == p_font) {
+ return;
+ }
+
+ fallback_font = p_font;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+Ref<Font> ThemeDB::get_fallback_font() {
+ return fallback_font;
+}
+
+void ThemeDB::set_fallback_font_size(int p_font_size) {
+ if (fallback_font_size == p_font_size) {
+ return;
+ }
+
+ fallback_font_size = p_font_size;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+int ThemeDB::get_fallback_font_size() {
+ return fallback_font_size;
+}
+
+void ThemeDB::set_fallback_icon(const Ref<Texture2D> &p_icon) {
+ if (fallback_icon == p_icon) {
+ return;
+ }
+
+ fallback_icon = p_icon;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+Ref<Texture2D> ThemeDB::get_fallback_icon() {
+ return fallback_icon;
+}
+
+void ThemeDB::set_fallback_stylebox(const Ref<StyleBox> &p_stylebox) {
+ if (fallback_stylebox == p_stylebox) {
+ return;
+ }
+
+ fallback_stylebox = p_stylebox;
+ emit_signal(SNAME("fallback_changed"));
+}
+
+Ref<StyleBox> ThemeDB::get_fallback_stylebox() {
+ return fallback_stylebox;
+}
+
+// Object methods.
+void ThemeDB::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("get_default_theme"), &ThemeDB::get_default_theme);
+ ClassDB::bind_method(D_METHOD("get_project_theme"), &ThemeDB::get_project_theme);
+
+ ClassDB::bind_method(D_METHOD("set_fallback_base_scale", "base_scale"), &ThemeDB::set_fallback_base_scale);
+ ClassDB::bind_method(D_METHOD("get_fallback_base_scale"), &ThemeDB::get_fallback_base_scale);
+ ClassDB::bind_method(D_METHOD("set_fallback_font", "font"), &ThemeDB::set_fallback_font);
+ ClassDB::bind_method(D_METHOD("get_fallback_font"), &ThemeDB::get_fallback_font);
+ ClassDB::bind_method(D_METHOD("set_fallback_font_size", "font_size"), &ThemeDB::set_fallback_font_size);
+ ClassDB::bind_method(D_METHOD("get_fallback_font_size"), &ThemeDB::get_fallback_font_size);
+ ClassDB::bind_method(D_METHOD("set_fallback_icon", "icon"), &ThemeDB::set_fallback_icon);
+ ClassDB::bind_method(D_METHOD("get_fallback_icon"), &ThemeDB::get_fallback_icon);
+ ClassDB::bind_method(D_METHOD("set_fallback_stylebox", "stylebox"), &ThemeDB::set_fallback_stylebox);
+ ClassDB::bind_method(D_METHOD("get_fallback_stylebox"), &ThemeDB::get_fallback_stylebox);
+
+ ADD_GROUP("Fallback values", "fallback_");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "fallback_base_scale", PROPERTY_HINT_RANGE, "0.0,2.0,0.01,or_greater"), "set_fallback_base_scale", "get_fallback_base_scale");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_font", PROPERTY_HINT_RESOURCE_TYPE, "Font", PROPERTY_USAGE_NONE), "set_fallback_font", "get_fallback_font");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fallback_font_size", PROPERTY_HINT_RANGE, "0,256,1,or_greater,suffix:px"), "set_fallback_font_size", "get_fallback_font_size");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D", PROPERTY_USAGE_NONE), "set_fallback_icon", "get_fallback_icon");
+ ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "fallback_stylebox", PROPERTY_HINT_RESOURCE_TYPE, "StyleBox", PROPERTY_USAGE_NONE), "set_fallback_stylebox", "get_fallback_stylebox");
+
+ ADD_SIGNAL(MethodInfo("fallback_changed"));
+}
+
+// Memory management, reference, and initialization
+ThemeDB *ThemeDB::singleton = nullptr;
+
+ThemeDB *ThemeDB::get_singleton() {
+ return singleton;
+}
+
+ThemeDB::ThemeDB() {
+ singleton = this;
+
+ // Universal default values, final fallback for every theme.
+ fallback_base_scale = 1.0;
+ fallback_font_size = 16;
+}
+
+ThemeDB::~ThemeDB() {
+ default_theme.unref();
+ project_theme.unref();
+
+ fallback_font.unref();
+ fallback_icon.unref();
+ fallback_stylebox.unref();
+
+ singleton = nullptr;
+}
diff --git a/scene/theme/theme_db.h b/scene/theme/theme_db.h
new file mode 100644
index 0000000000..aace33d82c
--- /dev/null
+++ b/scene/theme/theme_db.h
@@ -0,0 +1,95 @@
+/*************************************************************************/
+/* theme_db.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef THEME_DB_H
+#define THEME_DB_H
+
+#include "core/object/class_db.h"
+#include "core/object/ref_counted.h"
+
+class Font;
+class StyleBox;
+class Texture2D;
+class Theme;
+
+class ThemeDB : public Object {
+ GDCLASS(ThemeDB, Object);
+
+ static ThemeDB *singleton;
+
+ // Universal Theme resources used when no other theme has the item.
+ Ref<Theme> default_theme;
+ Ref<Theme> project_theme;
+
+ // Universal default values, final fallback for every theme.
+ float fallback_base_scale;
+ Ref<Font> fallback_font;
+ int fallback_font_size;
+ Ref<Texture2D> fallback_icon;
+ Ref<StyleBox> fallback_stylebox;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void initialize_theme();
+ void initialize_theme_noproject();
+
+ // Universal Theme resources
+
+ void set_default_theme(const Ref<Theme> &p_default);
+ Ref<Theme> get_default_theme();
+
+ void set_project_theme(const Ref<Theme> &p_project_default);
+ Ref<Theme> get_project_theme();
+
+ // Universal default values.
+
+ void set_fallback_base_scale(float p_base_scale);
+ float get_fallback_base_scale();
+
+ void set_fallback_font(const Ref<Font> &p_font);
+ Ref<Font> get_fallback_font();
+
+ void set_fallback_font_size(int p_font_size);
+ int get_fallback_font_size();
+
+ void set_fallback_icon(const Ref<Texture2D> &p_icon);
+ Ref<Texture2D> get_fallback_icon();
+
+ void set_fallback_stylebox(const Ref<StyleBox> &p_stylebox);
+ Ref<StyleBox> get_fallback_stylebox();
+
+ static ThemeDB *get_singleton();
+ ThemeDB();
+ ~ThemeDB();
+};
+
+#endif // THEME_DB_H