summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/animation_track_editor.cpp59
-rw-r--r--editor/animation_track_editor.h3
-rw-r--r--editor/editor_inspector.cpp358
-rw-r--r--editor/editor_inspector.h23
-rw-r--r--editor/editor_log.cpp4
-rw-r--r--editor/editor_node.cpp9
-rw-r--r--editor/editor_properties.cpp10
-rw-r--r--editor/editor_properties.h2
-rw-r--r--editor/editor_resource_picker.cpp2
-rw-r--r--editor/editor_themes.cpp4
-rw-r--r--editor/editor_toaster.cpp6
-rw-r--r--editor/icons/GradientTexture1D.svg (renamed from editor/icons/GradientTexture.svg)0
-rw-r--r--editor/icons/InterpCubic.svg2
-rw-r--r--editor/icons/InterpLinear.svg2
-rw-r--r--editor/icons/InterpWrapClamp.svg2
-rw-r--r--editor/icons/InterpWrapLoop.svg2
-rw-r--r--editor/icons/PingPongLoop.svg1
-rw-r--r--editor/icons/ReverseGradient.svg1
-rw-r--r--editor/icons/TrackCapture.svg2
-rw-r--r--editor/icons/TrackDiscrete.svg2
-rw-r--r--editor/icons/TrackTrigger.svg2
-rw-r--r--editor/import/editor_import_plugin.cpp2
-rw-r--r--editor/import/resource_importer_bmfont.cpp29
-rw-r--r--editor/import/resource_importer_obj.cpp8
-rw-r--r--editor/import/resource_importer_scene.cpp22
-rw-r--r--editor/import/resource_importer_wav.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp9
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp8
-rw-r--r--editor/plugins/gradient_editor_plugin.cpp45
-rw-r--r--editor/plugins/gradient_editor_plugin.h16
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/ot_features_plugin.cpp6
-rw-r--r--editor/plugins/ot_features_plugin.h2
-rw-r--r--editor/plugins/root_motion_editor_plugin.cpp12
-rw-r--r--editor/plugins/root_motion_editor_plugin.h2
-rw-r--r--editor/plugins/script_editor_plugin.cpp71
-rw-r--r--editor/plugins/script_editor_plugin.h1
-rw-r--r--editor/plugins/script_text_editor.cpp25
-rw-r--r--editor/plugins/style_box_editor_plugin.cpp7
-rw-r--r--editor/plugins/style_box_editor_plugin.h2
-rw-r--r--editor/plugins/text_control_editor_plugin.cpp375
-rw-r--r--editor/plugins/text_control_editor_plugin.h119
-rw-r--r--editor/plugins/text_editor.cpp25
-rw-r--r--editor/plugins/texture_3d_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/texture_layered_editor_plugin.cpp2
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp13
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h2
-rw-r--r--editor/rename_dialog.cpp6
-rw-r--r--editor/scene_tree_dock.cpp20
50 files changed, 969 insertions, 372 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index a85a4450a6..b15636f775 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -1377,8 +1377,20 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
void AnimationTimelineEdit::_anim_loop_pressed() {
undo_redo->create_action(TTR("Change Animation Loop"));
- undo_redo->add_do_method(animation.ptr(), "set_loop", loop->is_pressed());
- undo_redo->add_undo_method(animation.ptr(), "set_loop", animation->has_loop());
+ switch (animation->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_LINEAR);
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_PINGPONG);
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_NONE);
+ } break;
+ default:
+ break;
+ }
+ undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode());
undo_redo->commit_action();
}
@@ -1664,7 +1676,24 @@ void AnimationTimelineEdit::update_values() {
length->set_tooltip(TTR("Animation length (seconds)"));
time_icon->set_tooltip(TTR("Animation length (seconds)"));
}
- loop->set_pressed(animation->has_loop());
+
+ switch (animation->get_loop_mode()) {
+ case Animation::LoopMode::LOOP_NONE: {
+ loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
+ loop->set_pressed(false);
+ } break;
+ case Animation::LoopMode::LOOP_LINEAR: {
+ loop->set_icon(get_theme_icon("Loop", "EditorIcons"));
+ loop->set_pressed(true);
+ } break;
+ case Animation::LoopMode::LOOP_PINGPONG: {
+ loop->set_icon(get_theme_icon("PingPongLoop", "EditorIcons"));
+ loop->set_pressed(true);
+ } break;
+ default:
+ break;
+ }
+
editing = false;
}
@@ -2110,25 +2139,25 @@ void AnimationTrackEdit::_notification(int p_what) {
Ref<Texture2D> icon = wrap_icon[loop_wrap ? 1 : 0];
- loop_mode_rect.position.x = ofs;
- loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
- loop_mode_rect.size = icon->get_size();
+ loop_wrap_rect.position.x = ofs;
+ loop_wrap_rect.position.y = int(get_size().height - icon->get_height()) / 2;
+ loop_wrap_rect.size = icon->get_size();
if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
- draw_texture(icon, loop_mode_rect.position);
+ draw_texture(icon, loop_wrap_rect.position);
}
- loop_mode_rect.position.y = 0;
- loop_mode_rect.size.y = get_size().height;
+ loop_wrap_rect.position.y = 0;
+ loop_wrap_rect.size.y = get_size().height;
ofs += icon->get_width() + hsep;
- loop_mode_rect.size.x += hsep;
+ loop_wrap_rect.size.x += hsep;
if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
- loop_mode_rect.size.x += down_icon->get_width();
+ loop_wrap_rect.size.x += down_icon->get_width();
} else {
- loop_mode_rect = Rect2();
+ loop_wrap_rect = Rect2();
}
ofs += down_icon->get_width();
@@ -2478,7 +2507,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
return TTR("Interpolation Mode");
}
- if (loop_mode_rect.has_point(p_pos)) {
+ if (loop_wrap_rect.has_point(p_pos)) {
return TTR("Loop Wrap Mode (Interpolate end with beginning on loop)");
}
@@ -2681,7 +2710,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
accept_event();
}
- if (loop_mode_rect.has_point(pos)) {
+ if (loop_wrap_rect.has_point(pos)) {
if (!menu) {
menu = memnew(PopupMenu);
add_child(menu);
@@ -2692,7 +2721,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
menu->set_as_minsize();
- Vector2 popup_pos = get_screen_position() + loop_mode_rect.position + Vector2(0, loop_mode_rect.size.height);
+ Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height);
menu->set_position(popup_pos);
menu->popup();
accept_event();
diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h
index 05cf91de1d..2bdc1d4107 100644
--- a/editor/animation_track_editor.h
+++ b/editor/animation_track_editor.h
@@ -159,7 +159,7 @@ class AnimationTrackEdit : public Control {
Rect2 update_mode_rect;
Rect2 interp_mode_rect;
- Rect2 loop_mode_rect;
+ Rect2 loop_wrap_rect;
Rect2 remove_rect;
Rect2 bezier_edit_rect;
@@ -466,6 +466,7 @@ class AnimationTrackEditor : public VBoxContainer {
Animation::TrackType track_type = Animation::TrackType::TYPE_ANIMATION;
Animation::InterpolationType interp_type = Animation::InterpolationType::INTERPOLATION_CUBIC;
Animation::UpdateMode update_mode = Animation::UpdateMode::UPDATE_CAPTURE;
+ Animation::LoopMode loop_mode = Animation::LoopMode::LOOP_LINEAR;
bool loop_wrap = false;
bool enabled = false;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 16567cfebb..c8baecaaaf 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -39,6 +39,7 @@
#include "editor_scale.h"
#include "editor_settings.h"
#include "multi_node_edit.h"
+#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"
Size2 EditorProperty::get_minimum_size() const {
@@ -305,6 +306,20 @@ void EditorProperty::_notification(int p_what) {
revert_rect = Rect2();
}
+ if (!pin_hidden && pinned) {
+ Ref<Texture2D> pinned_icon = get_theme_icon(SNAME("Pin"), SNAME("EditorIcons"));
+ int margin_w = get_theme_constant(SNAME("hseparator"), SNAME("Tree")) * 2;
+ int total_icon_w = margin_w + pinned_icon->get_width();
+ int text_w = font->get_string_size(label, font_size, rtl ? HALIGN_RIGHT : HALIGN_LEFT, text_limit - total_icon_w).x;
+ int y = (size.height - pinned_icon->get_height()) / 2;
+ if (rtl) {
+ draw_texture(pinned_icon, Vector2(size.width - ofs - text_w - total_icon_w, y), color);
+ } else {
+ draw_texture(pinned_icon, Vector2(ofs + text_w + margin_w, y), color);
+ }
+ text_limit -= total_icon_w;
+ }
+
int v_ofs = (size.height - font->get_height(font_size)) / 2;
if (rtl) {
draw_string(font, Point2(size.width - ofs - text_limit, v_ofs + font->get_ascent(font_size)), label, HALIGN_RIGHT, text_limit, font_size, color);
@@ -398,177 +413,12 @@ bool EditorProperty::is_read_only() const {
return read_only;
}
-bool EditorPropertyRevert::may_node_be_in_instance(Node *p_node) {
- Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
-
- bool might_be = false;
- Node *node = p_node;
-
- while (node) {
- if (node == edited_scene) {
- if (node->get_scene_inherited_state().is_valid()) {
- might_be = true;
- break;
- }
- might_be = false;
- break;
- }
- if (node->get_scene_instance_state().is_valid()) {
- might_be = true;
- break;
- }
- node = node->get_owner();
- }
-
- return might_be; // or might not be
-}
-
-bool EditorPropertyRevert::get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default) {
- Node *node = p_node;
- Node *orig = node;
-
- Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
-
- bool found = false;
-
- while (node) {
- Ref<SceneState> ss;
-
- if (node == edited_scene) {
- ss = node->get_scene_inherited_state();
-
- } else {
- ss = node->get_scene_instance_state();
- }
-
- if (ss.is_valid()) {
- NodePath np = node->get_path_to(orig);
- int node_idx = ss->find_node_by_path(np);
- if (node_idx >= 0) {
- bool lfound = false;
- Variant lvar;
- lvar = ss->get_property_value(node_idx, p_prop, lfound);
- if (lfound) {
- found = true;
- value = lvar;
- }
- }
- }
- if (node == edited_scene) {
- //just in case
- break;
- }
- node = node->get_owner();
- }
-
- if (p_check_class_default && !found && p_node) {
- //if not found, try default class value
- Variant attempt = ClassDB::class_get_default_property_value(p_node->get_class_name(), p_prop);
- if (attempt.get_type() != Variant::NIL) {
- found = true;
- value = attempt;
- }
- }
-
- return found;
-}
-
-bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig) {
- // this is a pretty difficult function, because a property may not be saved but may have
- // the flag to not save if one or if zero
-
- //make sure there is an actual state
- {
- Node *node = p_node;
- if (!node) {
- return false;
- }
-
- Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
- bool found_state = false;
-
- while (node) {
- Ref<SceneState> ss;
-
- if (node == edited_scene) {
- ss = node->get_scene_inherited_state();
-
- } else {
- ss = node->get_scene_instance_state();
- }
-
- if (ss.is_valid()) {
- found_state = true;
- break;
- }
- if (node == edited_scene) {
- //just in case
- break;
- }
- node = node->get_owner();
- }
-
- if (!found_state) {
- return false; //pointless to check if we are not comparing against anything.
- }
- }
-
- return is_property_value_different(p_current, p_orig);
-}
-
-bool EditorPropertyRevert::is_property_value_different(const Variant &p_a, const Variant &p_b) {
- if (p_a.get_type() == Variant::FLOAT && p_b.get_type() == Variant::FLOAT) {
- //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
- return !Math::is_equal_approx((float)p_a, (float)p_b);
- } else {
- return p_a != p_b;
- }
-}
-
Variant EditorPropertyRevert::get_property_revert_value(Object *p_object, const StringName &p_property) {
- // If the object implements property_can_revert, rely on that completely
- // (i.e. don't then try to revert to default value - the property_get_revert implementation
- // can do that if so desired)
if (p_object->has_method("property_can_revert") && p_object->call("property_can_revert", p_property)) {
return p_object->call("property_get_revert", p_property);
}
- Ref<Script> scr = p_object->get_script();
- Node *node = Object::cast_to<Node>(p_object);
- if (node && EditorPropertyRevert::may_node_be_in_instance(node)) {
- //if this node is an instance or inherits, but it has a script attached which is unrelated
- //to the one set for the parent and also has a default value for the property, consider that
- //has precedence over the value from the parent, because that is an explicit source of defaults
- //closer in the tree to the current node
- bool ignore_parent = false;
- if (scr.is_valid()) {
- Variant sorig;
- if (EditorPropertyRevert::get_instantiated_node_original_property(node, "script", sorig) && !scr->inherits_script(sorig)) {
- Variant dummy;
- if (scr->get_property_default_value(p_property, dummy)) {
- ignore_parent = true;
- }
- }
- }
-
- if (!ignore_parent) {
- //check for difference including instantiation
- Variant vorig;
- if (EditorPropertyRevert::get_instantiated_node_original_property(node, p_property, vorig, false)) {
- return vorig;
- }
- }
- }
-
- if (scr.is_valid()) {
- Variant orig_value;
- if (scr->get_property_default_value(p_property, orig_value)) {
- return orig_value;
- }
- }
-
- //report default class value instead
- return ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property);
+ return PropertyUtils::get_property_default_value(p_object, p_property);
}
bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property) {
@@ -577,18 +427,25 @@ bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringNam
return false;
}
Variant current_value = p_object->get(p_property);
- return EditorPropertyRevert::is_property_value_different(current_value, revert_value);
+ return PropertyUtils::is_property_value_different(current_value, revert_value);
}
-void EditorProperty::update_reload_status() {
+void EditorProperty::update_revert_and_pin_status() {
if (property == StringName()) {
return; //no property, so nothing to do
}
- bool has_reload = EditorPropertyRevert::can_property_revert(object, property);
+ bool new_pinned = false;
+ if (can_pin) {
+ Node *node = Object::cast_to<Node>(object);
+ CRASH_COND(!node);
+ new_pinned = node->is_property_pinned(property);
+ }
+ bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property) && !is_read_only();
- if (has_reload != can_revert) {
- can_revert = has_reload;
+ if (new_can_revert != can_revert || new_pinned != pinned) {
+ can_revert = new_can_revert;
+ pinned = new_pinned;
update();
}
}
@@ -791,7 +648,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) {
emit_signal(SNAME("property_checked"), property, checked);
}
} else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) {
- _ensure_popup();
+ _update_popup();
menu->set_position(get_screen_position() + get_local_mouse_position());
menu->set_size(Vector2(1, 1));
menu->popup();
@@ -914,6 +771,56 @@ float EditorProperty::get_name_split_ratio() const {
void EditorProperty::set_object_and_property(Object *p_object, const StringName &p_property) {
object = p_object;
property = p_property;
+ _update_pin_flags();
+}
+
+static bool _is_value_potential_override(Node *p_node, const String &p_property) {
+ // Consider a value is potentially overriding another if either of the following is true:
+ // a) The node is foreign (inheriting or an instance), so the original value may come from another scene.
+ // b) The node belongs to the scene, but the original value comes from somewhere but the builtin class (i.e., a script).
+ Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
+ Vector<SceneState::PackState> states_stack = PropertyUtils::get_node_states_stack(p_node, edited_scene);
+ if (states_stack.size()) {
+ return true;
+ } else {
+ bool is_class_default = false;
+ PropertyUtils::get_property_default_value(p_node, p_property, &states_stack, false, nullptr, &is_class_default);
+ return !is_class_default;
+ }
+}
+
+void EditorProperty::_update_pin_flags() {
+ can_pin = false;
+ pin_hidden = true;
+ if (read_only) {
+ return;
+ }
+ if (Node *node = Object::cast_to<Node>(object)) {
+ // Avoid errors down the road by ignoring nodes which are not part of a scene
+ if (!node->get_owner()) {
+ bool is_scene_root = false;
+ for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_edited_scene_count(); ++i) {
+ if (EditorNode::get_singleton()->get_editor_data().get_edited_scene_root(i) == node) {
+ is_scene_root = true;
+ break;
+ }
+ }
+ if (!is_scene_root) {
+ return;
+ }
+ }
+ if (!_is_value_potential_override(node, property)) {
+ return;
+ }
+ pin_hidden = false;
+ {
+ Set<StringName> storable_properties;
+ node->get_storable_properties(storable_properties);
+ if (storable_properties.has(node->get_property_store_alias(property))) {
+ can_pin = true;
+ }
+ }
+ }
}
Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
@@ -955,6 +862,10 @@ void EditorProperty::menu_option(int p_option) {
case MENU_COPY_PROPERTY_PATH: {
DisplayServer::get_singleton()->clipboard_set(property);
} break;
+ case MENU_PIN_VALUE: {
+ emit_signal(SNAME("property_pinned"), property, !pinned);
+ update();
+ } break;
}
}
@@ -1003,12 +914,14 @@ void EditorProperty::_bind_methods() {
ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING_NAME, "property")));
ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property")));
ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
- ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::STRING, "bool")));
+ ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "checked")));
+ ADD_SIGNAL(MethodInfo("property_pinned", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "pinned")));
ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
GDVIRTUAL_BIND(_update_property)
+ ClassDB::bind_method(D_METHOD("_update_revert_and_pin_status"), &EditorProperty::update_revert_and_pin_status);
}
EditorProperty::EditorProperty() {
@@ -1027,6 +940,9 @@ EditorProperty::EditorProperty() {
revert_hover = false;
check_hover = false;
can_revert = false;
+ can_pin = false;
+ pin_hidden = false;
+ pinned = false;
use_folding = false;
property_usage = 0;
selected = false;
@@ -1038,17 +954,29 @@ EditorProperty::EditorProperty() {
set_process_unhandled_key_input(true);
}
-void EditorProperty::_ensure_popup() {
+void EditorProperty::_update_popup() {
if (menu) {
- return;
+ menu->clear();
+ } else {
+ menu = memnew(PopupMenu);
+ add_child(menu);
+ menu->connect("id_pressed", callable_mp(this, &EditorProperty::menu_option));
}
- menu = memnew(PopupMenu);
menu->add_shortcut(ED_GET_SHORTCUT("property_editor/copy_property"), MENU_COPY_PROPERTY);
menu->add_shortcut(ED_GET_SHORTCUT("property_editor/paste_property"), MENU_PASTE_PROPERTY);
menu->add_shortcut(ED_GET_SHORTCUT("property_editor/copy_property_path"), MENU_COPY_PROPERTY_PATH);
- menu->connect("id_pressed", callable_mp(this, &EditorProperty::menu_option));
menu->set_item_disabled(MENU_PASTE_PROPERTY, is_read_only());
- add_child(menu);
+ if (!pin_hidden) {
+ menu->add_separator();
+ if (can_pin) {
+ menu->add_check_item(TTR("Pin value"), MENU_PIN_VALUE);
+ menu->set_item_checked(menu->get_item_index(MENU_PIN_VALUE), pinned);
+ menu->set_item_tooltip(menu->get_item_index(MENU_PIN_VALUE), TTR("Pinning a value forces it to be saved even if it's equal to the default."));
+ } else {
+ menu->add_check_item(vformat(TTR("Pin value [Disabled because '%s' is editor-only]"), property), MENU_PIN_VALUE);
+ menu->set_item_disabled(menu->get_item_index(MENU_PIN_VALUE), true);
+ }
+ }
}
////////////////////////////////////////////////
@@ -1086,11 +1014,15 @@ bool EditorInspectorPlugin::can_handle(Object *p_object) {
}
void EditorInspectorPlugin::parse_begin(Object *p_object) {
- GDVIRTUAL_CALL(_parse_begin);
+ GDVIRTUAL_CALL(_parse_begin, p_object);
+}
+
+void EditorInspectorPlugin::parse_category(Object *p_object, const String &p_category) {
+ GDVIRTUAL_CALL(_parse_category, p_object, p_category);
}
-void EditorInspectorPlugin::parse_category(Object *p_object, const String &p_parse_category) {
- GDVIRTUAL_CALL(_parse_category, p_object, p_parse_category);
+void EditorInspectorPlugin::parse_group(Object *p_object, const String &p_group) {
+ GDVIRTUAL_CALL(_parse_group, p_object, p_group);
}
bool EditorInspectorPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
@@ -1101,8 +1033,8 @@ bool EditorInspectorPlugin::parse_property(Object *p_object, const Variant::Type
return false;
}
-void EditorInspectorPlugin::parse_end() {
- GDVIRTUAL_CALL(_parse_end);
+void EditorInspectorPlugin::parse_end(Object *p_object) {
+ GDVIRTUAL_CALL(_parse_end, p_object);
}
void EditorInspectorPlugin::_bind_methods() {
@@ -1111,10 +1043,11 @@ void EditorInspectorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_property_editor_for_multiple_properties", "label", "properties", "editor"), &EditorInspectorPlugin::add_property_editor_for_multiple_properties);
GDVIRTUAL_BIND(_can_handle, "object")
- GDVIRTUAL_BIND(_parse_begin)
+ GDVIRTUAL_BIND(_parse_begin, "object")
GDVIRTUAL_BIND(_parse_category, "object", "category")
+ GDVIRTUAL_BIND(_parse_group, "object", "group")
GDVIRTUAL_BIND(_parse_property, "object", "type", "name", "hint_type", "hint_string", "usage_flags", "wide");
- GDVIRTUAL_BIND(_parse_end)
+ GDVIRTUAL_BIND(_parse_end, "object")
}
////////////////////////////////////////////////
@@ -2296,6 +2229,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<Edit
ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), varray(), CONNECT_DEFERRED);
ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value));
ep->connect("property_checked", callable_mp(this, &EditorInspector::_property_checked));
+ ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned));
ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected));
ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed));
ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), varray(), CONNECT_DEFERRED);
@@ -2324,7 +2258,8 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<Edit
ep->set_read_only(read_only);
ep->update_property();
- ep->update_reload_status();
+ ep->_update_pin_flags();
+ ep->update_revert_and_pin_status();
ep->set_deletable(deletable_properties);
ep->update_cache();
}
@@ -2698,6 +2633,12 @@ void EditorInspector::update_tree() {
c.a /= level;
section->setup(acc_path, component, object, c, use_folding);
+ // Add editors at the start of a group.
+ for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
+ ped->parse_group(object, path);
+ _parse_added_editors(section->get_vbox(), ped);
+ }
+
vbox_per_path[root_vbox][acc_path] = section->get_vbox();
}
@@ -2877,6 +2818,7 @@ void EditorInspector::update_tree() {
ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), varray(), CONNECT_DEFERRED);
ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value));
ep->connect("property_checked", callable_mp(this, &EditorInspector::_property_checked));
+ ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned));
ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected));
ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed));
ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), varray(), CONNECT_DEFERRED);
@@ -2887,7 +2829,8 @@ void EditorInspector::update_tree() {
ep->set_tooltip(property_prefix + p.name);
}
ep->update_property();
- ep->update_reload_status();
+ ep->_update_pin_flags();
+ ep->update_revert_and_pin_status();
ep->update_cache();
if (current_selected && ep->property == current_selected) {
@@ -2905,7 +2848,7 @@ void EditorInspector::update_tree() {
// Get the lists of to add at the end.
for (Ref<EditorInspectorPlugin> &ped : valid_plugins) {
- ped->parse_end();
+ ped->parse_end(object);
_parse_added_editors(main_vbox, ped);
}
}
@@ -2917,7 +2860,7 @@ void EditorInspector::update_property(const String &p_prop) {
for (EditorProperty *E : editor_property_map[p_prop]) {
E->update_property();
- E->update_reload_status();
+ E->update_revert_and_pin_status();
E->update_cache();
}
}
@@ -3196,7 +3139,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
if (editor_property_map.has(p_name)) {
for (EditorProperty *E : editor_property_map[p_name]) {
- E->update_reload_status();
+ E->update_revert_and_pin_status();
}
}
}
@@ -3295,7 +3238,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
if (editor_property_map.has(p_path)) {
for (EditorProperty *E : editor_property_map[p_path]) {
E->update_property();
- E->update_reload_status();
+ E->update_revert_and_pin_status();
E->update_cache();
}
}
@@ -3305,6 +3248,35 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
}
}
+void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
+ if (!object) {
+ return;
+ }
+
+ Node *node = Object::cast_to<Node>(object);
+ ERR_FAIL_COND(!node);
+
+ if (undo_redo) {
+ undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
+ undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
+ undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
+ if (editor_property_map.has(p_path)) {
+ for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
+ undo_redo->add_do_method(E->get(), "_update_revert_and_pin_status");
+ undo_redo->add_undo_method(E->get(), "_update_revert_and_pin_status");
+ }
+ }
+ undo_redo->commit_action();
+ } else {
+ node->set_property_pinned(p_path, p_pinned);
+ if (editor_property_map.has(p_path)) {
+ for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
+ E->get()->update_revert_and_pin_status();
+ }
+ }
+ }
+}
+
void EditorInspector::_property_selected(const String &p_path, int p_focusable) {
property_selected = p_path;
property_focusable = p_focusable;
@@ -3375,7 +3347,7 @@ void EditorInspector::_notification(int p_what) {
for (EditorProperty *E : F.value) {
if (!E->is_cache_valid()) {
E->update_property();
- E->update_reload_status();
+ E->update_revert_and_pin_status();
E->update_cache();
}
}
@@ -3397,7 +3369,7 @@ void EditorInspector::_notification(int p_what) {
if (editor_property_map.has(prop)) {
for (EditorProperty *E : editor_property_map[prop]) {
E->update_property();
- E->update_reload_status();
+ E->update_revert_and_pin_status();
E->update_cache();
}
}
diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h
index 124ea31302..f2dfe32f82 100644
--- a/editor/editor_inspector.h
+++ b/editor/editor_inspector.h
@@ -43,7 +43,6 @@ class UndoRedo;
class EditorPropertyRevert {
public:
- static bool may_node_be_in_instance(Node *p_node);
static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true);
static bool is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig);
static bool is_property_value_different(const Variant &p_a, const Variant &p_b);
@@ -60,6 +59,7 @@ public:
MENU_COPY_PROPERTY,
MENU_PASTE_PROPERTY,
MENU_COPY_PROPERTY_PATH,
+ MENU_PIN_VALUE,
};
private:
@@ -91,11 +91,14 @@ private:
bool delete_hover = false;
bool can_revert;
+ bool can_pin;
+ bool pin_hidden;
+ bool pinned;
bool use_folding;
bool draw_top_bg;
- void _ensure_popup();
+ void _update_popup();
void _focusable_focused(int p_index);
bool selectable;
@@ -114,6 +117,8 @@ private:
Map<StringName, Variant> cache;
GDVIRTUAL0(_update_property)
+ void _update_pin_flags();
+
protected:
void _notification(int p_what);
static void _bind_methods();
@@ -138,7 +143,7 @@ public:
StringName get_edited_property();
virtual void update_property();
- void update_reload_status();
+ void update_revert_and_pin_status();
virtual bool use_keying_next() const;
@@ -210,10 +215,11 @@ protected:
static void _bind_methods();
GDVIRTUAL1RC(bool, _can_handle, Variant)
- GDVIRTUAL0(_parse_begin)
+ GDVIRTUAL1(_parse_begin, Object *)
GDVIRTUAL2(_parse_category, Object *, String)
+ GDVIRTUAL2(_parse_group, Object *, String)
GDVIRTUAL7R(bool, _parse_property, Object *, int, String, int, String, int, bool)
- GDVIRTUAL0(_parse_end)
+ GDVIRTUAL1(_parse_end, Object *)
public:
void add_custom_control(Control *control);
@@ -222,9 +228,10 @@ public:
virtual bool can_handle(Object *p_object);
virtual void parse_begin(Object *p_object);
- virtual void parse_category(Object *p_object, const String &p_parse_category);
+ virtual void parse_category(Object *p_object, const String &p_category);
+ virtual void parse_group(Object *p_object, const String &p_group);
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false);
- virtual void parse_end();
+ virtual void parse_end(Object *p_object);
};
class EditorInspectorCategory : public Control {
@@ -459,8 +466,8 @@ class EditorInspector : public ScrollContainer {
void _property_keyed(const String &p_path, bool p_advance);
void _property_keyed_with_value(const String &p_path, const Variant &p_value, bool p_advance);
void _property_deleted(const String &p_path);
-
void _property_checked(const String &p_path, bool p_checked);
+ void _property_pinned(const String &p_path, bool p_pinned);
void _resource_selected(const String &p_path, RES p_resource);
void _property_selected(const String &p_path, int p_focusable);
diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp
index 251e1c2385..5f2f8e91c9 100644
--- a/editor/editor_log.cpp
+++ b/editor/editor_log.cpp
@@ -45,9 +45,9 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f
String err_str;
if (p_errorexp && p_errorexp[0]) {
- err_str = p_errorexp;
+ err_str = String::utf8(p_errorexp);
} else {
- err_str = String(p_file) + ":" + itos(p_line) + " - " + String(p_error);
+ err_str = String::utf8(p_file) + ":" + itos(p_line) + " - " + String::utf8(p_error);
}
if (p_editor_notify) {
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 7db49c45dd..7d550d5c2f 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -174,6 +174,7 @@
#include "editor/plugins/sprite_frames_editor_plugin.h"
#include "editor/plugins/style_box_editor_plugin.h"
#include "editor/plugins/sub_viewport_preview_editor_plugin.h"
+#include "editor/plugins/text_control_editor_plugin.h"
#include "editor/plugins/text_editor.h"
#include "editor/plugins/texture_3d_editor_plugin.h"
#include "editor/plugins/texture_editor_plugin.h"
@@ -1716,8 +1717,10 @@ void EditorNode::_save_scene(String p_file, int idx) {
err = ResourceSaver::save(p_file, sdata, flg);
- _save_external_resources();
+ // This needs to be emitted before saving external resources.
+ emit_signal(SNAME("scene_saved"), p_file);
+ _save_external_resources();
editor_data.save_editor_external_data();
for (Ref<AnimatedValuesBackup> &E : anim_backups) {
@@ -3623,7 +3626,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
sdata->set_path(lpath, true); // take over path
}
- Node *new_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_MAIN);
+ Node *new_scene = sdata->instantiate(p_set_inherited ? PackedScene::GEN_EDIT_STATE_MAIN_INHERITED : PackedScene::GEN_EDIT_STATE_MAIN);
if (!new_scene) {
sdata.unref();
@@ -5711,6 +5714,7 @@ void EditorNode::_bind_methods() {
ADD_SIGNAL(MethodInfo("request_help_search"));
ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::PACKED_STRING_ARRAY, "args")));
ADD_SIGNAL(MethodInfo("resource_saved", PropertyInfo(Variant::OBJECT, "obj")));
+ ADD_SIGNAL(MethodInfo("scene_saved", PropertyInfo(Variant::STRING, "path")));
ADD_SIGNAL(MethodInfo("project_settings_changed"));
}
@@ -7010,6 +7014,7 @@ EditorNode::EditorNode() {
add_editor_plugin(memnew(GPUParticlesCollisionSDFEditorPlugin(this)));
add_editor_plugin(memnew(InputEventEditorPlugin(this)));
add_editor_plugin(memnew(SubViewportPreviewEditorPlugin(this)));
+ add_editor_plugin(memnew(TextControlEditorPlugin(this)));
for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) {
add_editor_plugin(EditorPlugins::create(i, this));
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 26f28ff5fb..a7b8e9c4d0 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -3170,11 +3170,7 @@ EditorPropertyResource::EditorPropertyResource() {
////////////// DEFAULT PLUGIN //////////////////////
bool EditorInspectorDefaultPlugin::can_handle(Object *p_object) {
- return true; //can handle everything
-}
-
-void EditorInspectorDefaultPlugin::parse_begin(Object *p_object) {
- //do none
+ return true; // Can handle everything.
}
bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
@@ -3185,10 +3181,6 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, const Varian
return false;
}
-void EditorInspectorDefaultPlugin::parse_end() {
- //do none
-}
-
struct EditorPropertyRangeHint {
bool angle_in_degrees = false;
bool greater = true;
diff --git a/editor/editor_properties.h b/editor/editor_properties.h
index 754d444309..42ef650adc 100644
--- a/editor/editor_properties.h
+++ b/editor/editor_properties.h
@@ -696,9 +696,7 @@ class EditorInspectorDefaultPlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
static EditorProperty *get_editor_for_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false);
};
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index f05c401f1d..4775ca418b 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -84,7 +84,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const
if (p_preview.is_valid()) {
preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(SNAME("normal"))->get_default_margin(SIDE_LEFT) + get_theme_constant(SNAME("hseparation"), SNAME("Button")));
- if (type == "GradientTexture") {
+ if (type == "GradientTexture1D") {
preview_rect->set_stretch_mode(TextureRect::STRETCH_SCALE);
assign_button->set_custom_minimum_size(Size2(1, 1));
} else {
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 06c39a957c..8e8437f1b2 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -1207,7 +1207,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0));
theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * EDSCALE);
theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * EDSCALE);
- theme->set_constant("shadow_as_outline", "RichTextLabel", 0 * EDSCALE);
+ theme->set_constant("shadow_outline_size", "RichTextLabel", 1 * EDSCALE);
theme->set_stylebox("focus", "RichTextLabel", make_empty_stylebox());
theme->set_stylebox("normal", "RichTextLabel", style_tree_bg);
@@ -1223,7 +1223,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0));
theme->set_constant("shadow_offset_x", "Label", 1 * EDSCALE);
theme->set_constant("shadow_offset_y", "Label", 1 * EDSCALE);
- theme->set_constant("shadow_as_outline", "Label", 0 * EDSCALE);
+ theme->set_constant("shadow_outline_size", "Label", 1 * EDSCALE);
theme->set_constant("line_spacing", "Label", 3 * EDSCALE);
// LinkButton
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index 22da12b59b..0d9a546b8e 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -158,11 +158,11 @@ void EditorToaster::_error_handler(void *p_self, const char *p_func, const char
if (p_editor_notify || (show_all_setting == 0 && in_dev) || show_all_setting == 1) {
String err_str;
if (p_errorexp && p_errorexp[0]) {
- err_str = p_errorexp;
+ err_str = String::utf8(p_errorexp);
} else {
- err_str = String(p_error);
+ err_str = String::utf8(p_error);
}
- String tooltip_str = String(p_file) + ":" + itos(p_line);
+ String tooltip_str = String::utf8(p_file) + ":" + itos(p_line);
if (!p_editor_notify) {
if (p_type == ERR_HANDLER_WARNING) {
diff --git a/editor/icons/GradientTexture.svg b/editor/icons/GradientTexture1D.svg
index fa03e69805..fa03e69805 100644
--- a/editor/icons/GradientTexture.svg
+++ b/editor/icons/GradientTexture1D.svg
diff --git a/editor/icons/InterpCubic.svg b/editor/icons/InterpCubic.svg
index ad2ed51ee1..b542986ea6 100644
--- a/editor/icons/InterpCubic.svg
+++ b/editor/icons/InterpCubic.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c3 0 3-4 6-4s3 4 6 4" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-4 6-4s1 4 6 4" fill="none" stroke="#5fb2ff" stroke-linecap="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg>
diff --git a/editor/icons/InterpLinear.svg b/editor/icons/InterpLinear.svg
index 241a82fc8f..966ddfdc31 100644
--- a/editor/icons/InterpLinear.svg
+++ b/editor/icons/InterpLinear.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 6-4 6 4" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 6-4 6 4" fill="none" stroke="#ffca5f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg>
diff --git a/editor/icons/InterpWrapClamp.svg b/editor/icons/InterpWrapClamp.svg
index 6ba8e78500..b589542019 100644
--- a/editor/icons/InterpWrapClamp.svg
+++ b/editor/icons/InterpWrapClamp.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v6h2v-2.9863-3.0137zm2 3.0137a1.0001 1.0001 0 0 0 .29297.69336l2 2a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-.29297-.29297h3.1719l-.29297.29297a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 .29297-.72266 1.0001 1.0001 0 0 0 -.29297-.69141l-2-2a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l.29297.29297h-3.1719l.29297-.29297a1 1 0 0 0 0-1.4141 1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102l-2 2a1.0001 1.0001 0 0 0 -.29297.7207zm10-.029297v3.0156h2v-6h-2z" fill="#e0e0e0"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v6h2v-2.9863-3.0137zm2 3.0137a1.0001 1.0001 0 0 0 .29297.69336l2 2a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-.29297-.29297h3.1719l-.29297.29297a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 .29297-.72266 1.0001 1.0001 0 0 0 -.29297-.69141l-2-2a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l.29297.29297h-3.1719l.29297-.29297a1 1 0 0 0 0-1.4141 1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102l-2 2a1.0001 1.0001 0 0 0 -.29297.7207zm10-.029297v3.0156h2v-6h-2z" fill="#fc7f7f"/></svg>
diff --git a/editor/icons/InterpWrapLoop.svg b/editor/icons/InterpWrapLoop.svg
index 57670f97ce..4faf7805f8 100644
--- a/editor/icons/InterpWrapLoop.svg
+++ b/editor/icons/InterpWrapLoop.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 0-3 2 3 2v-1h3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3h-3zm-5 1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h3v1l3-2-3-2v1h-3a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#e0e0e0"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 0-3 2 3 2v-1h3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3h-3zm-5 1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h3v1l3-2-3-2v1h-3a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#c38ef1"/></svg>
diff --git a/editor/icons/PingPongLoop.svg b/editor/icons/PingPongLoop.svg
new file mode 100644
index 0000000000..c44f889b49
--- /dev/null
+++ b/editor/icons/PingPongLoop.svg
@@ -0,0 +1 @@
+<svg enable-background="new 0 0 16 16" height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0" fill-opacity=".9961"><path d="m10 7h-4v-2l-4 3 4 3v-2h4v2l4-3-4-3z"/><path d="m0 1v14h2v-7-7z"/><path d="m14 1v7 7h2v-14z"/></g></svg>
diff --git a/editor/icons/ReverseGradient.svg b/editor/icons/ReverseGradient.svg
new file mode 100644
index 0000000000..12f80d12dd
--- /dev/null
+++ b/editor/icons/ReverseGradient.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="b" x1=".26458" x2="3.9688" y1=".79375" y2=".79375" gradientTransform="scale(3.7795)" gradientUnits="userSpaceOnUse"><stop stop-color="#ccc" offset="0"/><stop stop-color="#ccc" stop-opacity="0" offset="1"/></linearGradient><linearGradient id="a" x1=".26458" x2="3.9688" y1="3.4396" y2="3.4396" gradientTransform="matrix(3.7795 0 0 3.7795 -16 -1.1865e-7)" gradientUnits="userSpaceOnUse"><stop stop-color="#ccc" offset="0"/><stop stop-color="#ccc" stop-opacity="0" offset="1"/></linearGradient></defs><g><rect x="1" y="1" width="14" height="4" ry="1" fill="url(#b)"/><rect transform="scale(-1,1)" x="-15" y="11" width="14" height="4" ry="1" fill="url(#a)" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.7795"/><path d="m6 6 2 4 2-4z" fill="#ccc"/></g></svg>
diff --git a/editor/icons/TrackCapture.svg b/editor/icons/TrackCapture.svg
index aaa4a20e4a..b3d5f09eff 100644
--- a/editor/icons/TrackCapture.svg
+++ b/editor/icons/TrackCapture.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m2.1665128.99764963c-.422625 0-.763672.34104737-.763672.76367187v4.5742187c0 .4226242.341047.7617192.763672.7617192h4.472656c.422625 0 .763672-.339095.763672-.7617192v-.9882812h-3.300781c-.1662 0-.298828-.3390943-.298828-.7617188v-1.2246094c0-.4226244.132628-.7636718.298828-.7636718h3.300781v-.8359375c0-.4226245-.341047-.76367187-.763672-.76367187z"/><path d="m9.1827441 4.7953408c.5166221-1.0415625 1.0955249-2.2117429 1.2864509-2.600401l.347137-.7066511.679654.00665.679654.00665.956945 2.3125c.526319 1.271875 1.007254 2.4334375 1.068744 2.5812497l.1118.26875h-.597215-.597214l-.332849-.6437497-.332849-.64375h-1.133826-1.133825l-.3786749.6561133-.3786747.6561134-.5922856.000137-.592285.000136zm3.1779349-.369483c.0042-.00346-.233487-.4884588-.528245-1.0777779l-.535922-1.0714891-.03691.0875c-.0203.048125-.183516.425-.362699.8375-.179182.4125-.355738.85125-.392346.975-.03661.12375-.07127.2390723-.07703.2562715-.0083.024853.188215.027989.957503.015278.532385-.0088.971429-.018823.975651-.022283z" stroke="#e0e0e0" stroke-width=".803"/></g></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e1da5b"><path d="m2.1665128.99764963c-.422625 0-.763672.34104737-.763672.76367187v4.5742187c0 .4226242.341047.7617192.763672.7617192h4.472656c.422625 0 .763672-.339095.763672-.7617192v-.9882812h-3.300781c-.1662 0-.298828-.3390943-.298828-.7617188v-1.2246094c0-.4226244.132628-.7636718.298828-.7636718h3.300781v-.8359375c0-.4226245-.341047-.76367187-.763672-.76367187z"/><path d="m9.1827441 4.7953408c.5166221-1.0415625 1.0955249-2.2117429 1.2864509-2.600401l.347137-.7066511.679654.00665.679654.00665.956945 2.3125c.526319 1.271875 1.007254 2.4334375 1.068744 2.5812497l.1118.26875h-.597215-.597214l-.332849-.6437497-.332849-.64375h-1.133826-1.133825l-.3786749.6561133-.3786747.6561134-.5922856.000137-.592285.000136zm3.1779349-.369483c.0042-.00346-.233487-.4884588-.528245-1.0777779l-.535922-1.0714891-.03691.0875c-.0203.048125-.183516.425-.362699.8375-.179182.4125-.355738.85125-.392346.975-.03661.12375-.07127.2390723-.07703.2562715-.0083.024853.188215.027989.957503.015278.532385-.0088.971429-.018823.975651-.022283z" stroke="#e1da5b" stroke-width=".803"/></g></svg>
diff --git a/editor/icons/TrackDiscrete.svg b/editor/icons/TrackDiscrete.svg
index d1df4b1667..6498742233 100644
--- a/editor/icons/TrackDiscrete.svg
+++ b/editor/icons/TrackDiscrete.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#b9ec41"/></svg>
diff --git a/editor/icons/TrackTrigger.svg b/editor/icons/TrackTrigger.svg
index 6e46a74121..c403fba59a 100644
--- a/editor/icons/TrackTrigger.svg
+++ b/editor/icons/TrackTrigger.svg
@@ -1 +1 @@
-<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v4h2v-4h2v-2zm13 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg>
+<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v4h2v-4h2v-2zm13 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#f68f45"/></svg>
diff --git a/editor/import/editor_import_plugin.cpp b/editor/import/editor_import_plugin.cpp
index d219f6e325..2c1d2149c6 100644
--- a/editor/import/editor_import_plugin.cpp
+++ b/editor/import/editor_import_plugin.cpp
@@ -57,6 +57,7 @@ void EditorImportPlugin::get_recognized_extensions(List<String> *p_extensions) c
for (int i = 0; i < extensions.size(); i++) {
p_extensions->push_back(extensions[i]);
}
+ return;
}
ERR_FAIL_MSG("Unimplemented _get_recognized_extensions in add-on.");
}
@@ -139,6 +140,7 @@ void EditorImportPlugin::get_import_options(List<ResourceImporter::ImportOption>
ImportOption option(PropertyInfo(default_value.get_type(), name, hint, hint_string, usage), default_value);
r_options->push_back(option);
}
+ return;
}
ERR_FAIL_MSG("Unimplemented _get_import_options in add-on.");
diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp
index 2e7ef1402b..a64be54f2d 100644
--- a/editor/import/resource_importer_bmfont.cpp
+++ b/editor/import/resource_importer_bmfont.cpp
@@ -359,6 +359,8 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String &
int height = 0;
int ascent = 0;
int outline = 0;
+ uint32_t st_flags = 0;
+ String font_name;
bool packed = false;
uint8_t ch[4] = { 0, 0, 0, 0 }; // RGBA
@@ -382,13 +384,23 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String &
base_size = f->get_16();
uint8_t flags = f->get_8();
ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported."));
+ if (flags & (1 << 3)) {
+ st_flags |= TextServer::FONT_BOLD;
+ }
+ if (flags & (1 << 2)) {
+ st_flags |= TextServer::FONT_ITALIC;
+ }
f->get_8(); // non-unicode charset, skip
f->get_16(); // stretch_h, skip
f->get_8(); // aa, skip
f->get_32(); // padding, skip
f->get_16(); // spacing, skip
outline = f->get_8();
- // font name, skip
+ // font name
+ PackedByteArray name_data;
+ name_data.resize(block_size - 14);
+ f->get_buffer(name_data.ptrw(), block_size - 14);
+ font_name = String::utf8((const char *)name_data.ptr(), block_size - 14);
font->set_fixed_size(base_size);
} break;
case 2: /* common */ {
@@ -601,6 +613,19 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String &
if (keys.has("outline")) {
outline = keys["outline"].to_int();
}
+ if (keys.has("bold")) {
+ if (keys["bold"].to_int()) {
+ st_flags |= TextServer::FONT_BOLD;
+ }
+ }
+ if (keys.has("italic")) {
+ if (keys["italic"].to_int()) {
+ st_flags |= TextServer::FONT_ITALIC;
+ }
+ }
+ if (keys.has("face")) {
+ font_name = keys["face"];
+ }
ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported."));
} else if (type == "common") {
if (keys.has("lineHeight")) {
@@ -778,6 +803,8 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String &
}
}
+ font->set_font_name(font_name);
+ font->set_font_style(st_flags);
font->set_ascent(0, base_size, ascent);
font->set_descent(0, base_size, height - ascent);
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index 01af75c338..8eab27b533 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -405,11 +405,11 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
current_material_library = l.replace("mtllib", "").strip_edges();
if (!material_map.has(current_material_library)) {
Map<String, Ref<StandardMaterial3D>> lib;
- Error err = _parse_material_library(current_material_library, lib, r_missing_deps);
- if (err == ERR_CANT_OPEN) {
- String dir = p_path.get_base_dir();
- err = _parse_material_library(dir.plus_file(current_material_library), lib, r_missing_deps);
+ String lib_path = current_material_library;
+ if (lib_path.is_relative_path()) {
+ lib_path = p_path.get_base_dir().plus_file(current_material_library);
}
+ Error err = _parse_material_library(lib_path, lib, r_missing_deps);
if (err == OK) {
material_map[current_material_library] = lib;
}
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index 5efb08b95d..11639314d6 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -424,10 +424,10 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I
String animname = E;
const int loop_string_count = 3;
- static const char *loop_strings[loop_string_count] = { "loops", "loop", "cycle" };
+ static const char *loop_strings[loop_string_count] = { "loop_mode", "loop", "cycle" };
for (int i = 0; i < loop_string_count; i++) {
if (_teststr(animname, loop_strings[i])) {
- anim->set_loop(true);
+ anim->set_loop_mode(Animation::LoopMode::LOOP_LINEAR);
animname = _fixstr(animname, loop_strings[i]);
ap->rename_animation(E, animname);
}
@@ -868,7 +868,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
String name = node_settings["clip_" + itos(i + 1) + "/name"];
int from_frame = node_settings["clip_" + itos(i + 1) + "/start_frame"];
int end_frame = node_settings["clip_" + itos(i + 1) + "/end_frame"];
- bool loop = node_settings["clip_" + itos(i + 1) + "/loops"];
+ Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)node_settings["clip_" + itos(i + 1) + "/loop_mode"]);
bool save_to_file = node_settings["clip_" + itos(i + 1) + "/save_to_file/enabled"];
bool save_to_path = node_settings["clip_" + itos(i + 1) + "/save_to_file/path"];
bool save_to_file_keep_custom = node_settings["clip_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"];
@@ -876,7 +876,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
animation_clips.push_back(name);
animation_clips.push_back(from_frame / p_animation_fps);
animation_clips.push_back(end_frame / p_animation_fps);
- animation_clips.push_back(loop);
+ animation_clips.push_back(loop_mode);
animation_clips.push_back(save_to_file);
animation_clips.push_back(save_to_path);
animation_clips.push_back(save_to_file_keep_custom);
@@ -903,7 +903,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref<
}
}
- anim->set_loop(anim_settings["settings/loops"]);
+ anim->set_loop_mode(static_cast<Animation::LoopMode>((int)anim_settings["settings/loop_mode"]));
bool save = anim_settings["save_to_file/enabled"];
String path = anim_settings["save_to_file/path"];
bool keep_custom = anim_settings["save_to_file/keep_custom_tracks"];
@@ -977,7 +977,7 @@ Ref<Animation> ResourceImporterScene::_save_animation_to_file(Ref<Animation> ani
old_anim->copy_track(i, anim);
}
}
- anim->set_loop(old_anim->has_loop());
+ anim->set_loop_mode(old_anim->get_loop_mode());
}
}
@@ -1005,7 +1005,7 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
String name = p_clips[i];
float from = p_clips[i + 1];
float to = p_clips[i + 2];
- bool loop = p_clips[i + 3];
+ Animation::LoopMode loop_mode = static_cast<Animation::LoopMode>((int)p_clips[i + 3]);
bool save_to_file = p_clips[i + 4];
String save_to_path = p_clips[i + 5];
bool keep_current = p_clips[i + 6];
@@ -1135,7 +1135,7 @@ void ResourceImporterScene::_create_clips(AnimationPlayer *anim, const Array &p_
}
}
- new_anim->set_loop(loop);
+ new_anim->set_loop_mode(loop_mode);
new_anim->set_length(to - from);
anim->add_animation(name, new_anim);
@@ -1218,7 +1218,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "use_external/path", PROPERTY_HINT_FILE, "*.material,*.res,*.tres"), ""));
} break;
case INTERNAL_IMPORT_CATEGORY_ANIMATION: {
- r_options->push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "settings/loops"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "settings/loop_mode"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "save_to_file/path", PROPERTY_HINT_SAVE_FILE, "*.res,*.tres"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "save_to_file/keep_custom_tracks"), ""));
@@ -1240,7 +1240,7 @@ void ResourceImporterScene::get_internal_import_options(InternalImportCategory p
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/name"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/start_frame"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/end_frame"), 0));
- r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/loops"), false));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "slice_" + itos(i + 1) + "/loop_mode"), 0));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), false));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "slice_" + itos(i + 1) + "/save_to_file/path", PROPERTY_HINT_SAVE_FILE, ".res,*.tres"), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "slice_" + itos(i + 1) + "/save_to_file/keep_custom_tracks"), false));
@@ -1428,7 +1428,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in
r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "meshes/lightmap_texel_size", PROPERTY_HINT_RANGE, "0.001,100,0.001"), 0.1));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true));
r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true));
- r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15));
+ r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30));
r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), ""));
r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary()));
diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp
index 89383d3dde..877bdd50fb 100644
--- a/editor/import/resource_importer_wav.cpp
+++ b/editor/import/resource_importer_wav.cpp
@@ -272,7 +272,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s
if (loop_type == 0x00) {
loop = AudioStreamSample::LOOP_FORWARD;
} else if (loop_type == 0x01) {
- loop = AudioStreamSample::LOOP_PING_PONG;
+ loop = AudioStreamSample::LOOP_PINGPONG;
} else if (loop_type == 0x02) {
loop = AudioStreamSample::LOOP_BACKWARD;
}
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index ea025dad3e..65238446f9 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -41,6 +41,7 @@
#include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning.
#include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning.
#include "scene/main/window.h"
+#include "scene/resources/animation.h"
#include "servers/rendering_server.h"
void AnimationPlayerEditor::_node_removed(Node *p_node) {
@@ -72,7 +73,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
if (player->has_animation(animname)) {
Ref<Animation> anim = player->get_animation(animname);
if (!anim.is_null()) {
- frame->set_max(anim->get_length());
+ frame->set_max((double)anim->get_length());
}
}
}
@@ -289,7 +290,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
track_editor->set_root(root);
}
}
- frame->set_max(anim->get_length());
+ frame->set_max((double)anim->get_length());
} else {
track_editor->set_animation(Ref<Animation>());
@@ -1014,7 +1015,7 @@ void AnimationPlayerEditor::_seek_value_changed(float p_value, bool p_set, bool
Ref<Animation> anim;
anim = player->get_animation(current);
- float pos = CLAMP(anim->get_length() * (p_value / frame->get_max()), 0, anim->get_length());
+ float pos = CLAMP((double)anim->get_length() * (p_value / frame->get_max()), 0, (double)anim->get_length());
if (track_editor->is_snap_enabled()) {
pos = Math::snapped(pos, _get_editor_step());
}
@@ -1424,7 +1425,7 @@ void AnimationPlayerEditor::_prepare_onion_layers_2() {
float pos = cpos + step_off * anim->get_step();
- bool valid = anim->has_loop() || (pos >= 0 && pos <= anim->get_length());
+ bool valid = anim->get_loop_mode() != Animation::LoopMode::LOOP_NONE || (pos >= 0 && pos <= anim->get_length());
onion.captures_valid.write[cidx] = valid;
if (valid) {
player->seek(pos, true);
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 3710b26d1e..061483decf 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -2264,9 +2264,9 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) {
}
}
- if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_ctrl_pressed()) {
- add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position()));
+ if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT) {
add_node_menu->set_size(Vector2(1, 1));
+ add_node_menu->set_position(get_screen_position() + b->get_position());
add_node_menu->popup();
node_create_position = transform.affine_inverse().xform((get_local_mouse_position()));
return true;
@@ -6192,14 +6192,14 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte
label = memnew(Label);
label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1));
- label->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
+ label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE);
label->hide();
canvas_item_editor->get_controls_container()->add_child(label);
label_desc = memnew(Label);
label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1));
label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1));
- label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE);
+ label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE);
label_desc->add_theme_constant_override("line_spacing", 0);
label_desc->hide();
canvas_item_editor->get_controls_container()->add_child(label_desc);
diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp
index 355bdb69d8..da050abc02 100644
--- a/editor/plugins/gradient_editor_plugin.cpp
+++ b/editor/plugins/gradient_editor_plugin.cpp
@@ -46,6 +46,8 @@ void GradientEditor::_gradient_changed() {
editing = true;
Vector<Gradient::Point> points = gradient->get_points();
set_points(points);
+ set_interpolation_mode(gradient->get_interpolation_mode());
+ update();
editing = false;
}
@@ -55,8 +57,10 @@ void GradientEditor::_ramp_changed() {
undo_redo->create_action(TTR("Gradient Edited"));
undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets());
undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors());
+ undo_redo->add_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode());
undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets());
undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors());
+ undo_redo->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode());
undo_redo->commit_action();
editing = false;
}
@@ -69,6 +73,14 @@ void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) {
connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed));
gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed));
set_points(gradient->get_points());
+ set_interpolation_mode(gradient->get_interpolation_mode());
+}
+
+void GradientEditor::reverse_gradient() {
+ gradient->reverse();
+ set_points(gradient->get_points());
+ emit_signal(SNAME("ramp_changed"));
+ update();
}
GradientEditor::GradientEditor() {
@@ -77,6 +89,23 @@ GradientEditor::GradientEditor() {
///////////////////////
+void GradientReverseButton::_notification(int p_what) {
+ if (p_what == NOTIFICATION_DRAW) {
+ Ref<Texture2D> icon = get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons"));
+ if (is_pressed()) {
+ draw_texture_rect(icon, Rect2(margin, margin, icon->get_width(), icon->get_height()), false, get_theme_color(SNAME("icon_pressed_color"), SNAME("Button")));
+ } else {
+ draw_texture_rect(icon, Rect2(margin, margin, icon->get_width(), icon->get_height()));
+ }
+ }
+}
+
+Size2 GradientReverseButton::get_minimum_size() const {
+ return (get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons"))->get_size() + Size2(margin * 2, margin * 2));
+}
+
+///////////////////////
+
bool EditorInspectorPluginGradient::can_handle(Object *p_object) {
return Object::cast_to<Gradient>(p_object) != nullptr;
}
@@ -85,9 +114,23 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) {
Gradient *gradient = Object::cast_to<Gradient>(p_object);
Ref<Gradient> g(gradient);
- GradientEditor *editor = memnew(GradientEditor);
+ editor = memnew(GradientEditor);
editor->set_gradient(g);
add_custom_control(editor);
+
+ reverse_btn = memnew(GradientReverseButton);
+
+ gradient_tools_hbox = memnew(HBoxContainer);
+ gradient_tools_hbox->add_child(reverse_btn);
+
+ add_custom_control(gradient_tools_hbox);
+
+ reverse_btn->connect("pressed", callable_mp(this, &EditorInspectorPluginGradient::_reverse_button_pressed));
+ reverse_btn->set_tooltip(TTR("Reverse/mirror gradient."));
+}
+
+void EditorInspectorPluginGradient::_reverse_button_pressed() {
+ editor->reverse_gradient();
}
GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) {
diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h
index bcbb86e422..95b7b466c9 100644
--- a/editor/plugins/gradient_editor_plugin.h
+++ b/editor/plugins/gradient_editor_plugin.h
@@ -50,12 +50,28 @@ protected:
public:
virtual Size2 get_minimum_size() const override;
void set_gradient(const Ref<Gradient> &p_gradient);
+ void reverse_gradient();
GradientEditor();
};
+class GradientReverseButton : public BaseButton {
+ GDCLASS(GradientReverseButton, BaseButton);
+
+ int margin = 2;
+
+ void _notification(int p_what);
+ virtual Size2 get_minimum_size() const override;
+};
+
class EditorInspectorPluginGradient : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginGradient, EditorInspectorPlugin);
+ GradientEditor *editor;
+ HBoxContainer *gradient_tools_hbox;
+ GradientReverseButton *reverse_btn;
+
+ void _reverse_button_pressed();
+
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index fa5381bb10..5b1cbe6f00 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -2245,12 +2245,14 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
_menu_option(VIEW_RIGHT);
}
if (ED_IS_SHORTCUT("spatial_editor/orbit_view_down", p_event)) {
- cursor.x_rot -= Math_PI / 12.0;
+ // Clamp rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
+ cursor.x_rot = CLAMP(cursor.x_rot - Math_PI / 12.0, -1.57, 1.57);
view_type = VIEW_TYPE_USER;
_update_name();
}
if (ED_IS_SHORTCUT("spatial_editor/orbit_view_up", p_event)) {
- cursor.x_rot += Math_PI / 12.0;
+ // Clamp rotation to roughly -90..90 degrees so the user can't look upside-down and end up disoriented.
+ cursor.x_rot = CLAMP(cursor.x_rot + Math_PI / 12.0, -1.57, 1.57);
view_type = VIEW_TYPE_USER;
_update_name();
}
@@ -2885,13 +2887,13 @@ void Node3DEditorViewport::_notification(int p_what) {
// Color labels depending on performance level ("good" = green, "OK" = yellow, "bad" = red).
// Middle point is at 15 ms.
- cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), rtos(cpu_time).pad_decimals(1)));
+ cpu_time_label->set_text(vformat(TTR("CPU Time: %s ms"), rtos(cpu_time).pad_decimals(2)));
cpu_time_label->add_theme_color_override(
"font_color",
frame_time_gradient->get_color_at_offset(
Math::range_lerp(cpu_time, 0, 30, 0, 1)));
- gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(1)));
+ gpu_time_label->set_text(vformat(TTR("GPU Time: %s ms"), rtos(gpu_time).pad_decimals(2)));
// Middle point is at 15 ms.
gpu_time_label->add_theme_color_override(
"font_color",
diff --git a/editor/plugins/ot_features_plugin.cpp b/editor/plugins/ot_features_plugin.cpp
index fd42bce06e..c949621e28 100644
--- a/editor/plugins/ot_features_plugin.cpp
+++ b/editor/plugins/ot_features_plugin.cpp
@@ -185,12 +185,6 @@ bool EditorInspectorPluginOpenTypeFeatures::can_handle(Object *p_object) {
return (Object::cast_to<Control>(p_object) != nullptr);
}
-void EditorInspectorPluginOpenTypeFeatures::parse_begin(Object *p_object) {
-}
-
-void EditorInspectorPluginOpenTypeFeatures::parse_category(Object *p_object, const String &p_parse_category) {
-}
-
bool EditorInspectorPluginOpenTypeFeatures::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
if (p_path == "opentype_features/_new") {
OpenTypeFeaturesAdd *editor = memnew(OpenTypeFeaturesAdd);
diff --git a/editor/plugins/ot_features_plugin.h b/editor/plugins/ot_features_plugin.h
index dbafa3bbf6..add491ed48 100644
--- a/editor/plugins/ot_features_plugin.h
+++ b/editor/plugins/ot_features_plugin.h
@@ -86,8 +86,6 @@ class EditorInspectorPluginOpenTypeFeatures : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
- virtual void parse_category(Object *p_object, const String &p_parse_category) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
};
diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp
index ed91f174d1..0f3c50a861 100644
--- a/editor/plugins/root_motion_editor_plugin.cpp
+++ b/editor/plugins/root_motion_editor_plugin.cpp
@@ -271,11 +271,7 @@ EditorPropertyRootMotion::EditorPropertyRootMotion() {
//////////////////////////
bool EditorInspectorRootMotionPlugin::can_handle(Object *p_object) {
- return true; //can handle everything
-}
-
-void EditorInspectorRootMotionPlugin::parse_begin(Object *p_object) {
- //do none
+ return true; // Can handle everything.
}
bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
@@ -288,9 +284,5 @@ bool EditorInspectorRootMotionPlugin::parse_property(Object *p_object, const Var
return true;
}
- return false; //can be overridden, although it will most likely be last anyway
-}
-
-void EditorInspectorRootMotionPlugin::parse_end() {
- //do none
+ return false;
}
diff --git a/editor/plugins/root_motion_editor_plugin.h b/editor/plugins/root_motion_editor_plugin.h
index 1484af62e8..c05975b6c3 100644
--- a/editor/plugins/root_motion_editor_plugin.h
+++ b/editor/plugins/root_motion_editor_plugin.h
@@ -64,9 +64,7 @@ class EditorInspectorRootMotionPlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
};
#endif // ROOT_MOTION_EDITOR_PLUGIN_H
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 5485fcf6bc..dbd5b32e3c 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -989,10 +989,6 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
RES script = se->get_edited_resource();
- if (script->is_built_in()) {
- continue; //internal script, who cares
- }
-
if (script == p_res) {
se->tag_saved_version();
}
@@ -1002,6 +998,31 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) {
_trigger_live_script_reload();
}
+void ScriptEditor::_scene_saved_callback(const String &p_path) {
+ // If scene was saved, mark all built-in scripts from that scene as saved.
+ for (int i = 0; i < tab_container->get_child_count(); i++) {
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ if (!se) {
+ continue;
+ }
+
+ RES edited_res = se->get_edited_resource();
+
+ if (!edited_res->is_built_in()) {
+ continue; // External script, who cares.
+ }
+
+ if (edited_res->get_path().get_slice("::", 0) == p_path) {
+ se->tag_saved_version();
+ }
+
+ Ref<Script> scr = edited_res;
+ if (scr.is_valid() && scr->is_tool()) {
+ scr->reload(true);
+ }
+ }
+}
+
void ScriptEditor::_trigger_live_script_reload() {
if (!pending_auto_reload && auto_reload_running_scripts) {
call_deferred(SNAME("_live_auto_reload_running_scripts"));
@@ -1525,6 +1546,7 @@ void ScriptEditor::_notification(int p_what) {
editor->connect("stop_pressed", callable_mp(this, &ScriptEditor::_editor_stop));
editor->connect("script_add_function_request", callable_mp(this, &ScriptEditor::_add_callback));
editor->connect("resource_saved", callable_mp(this, &ScriptEditor::_res_saved_callback));
+ editor->connect("scene_saved", callable_mp(this, &ScriptEditor::_scene_saved_callback));
editor->get_filesystem_dock()->connect("files_moved", callable_mp(this, &ScriptEditor::_files_moved));
editor->get_filesystem_dock()->connect("file_removed", callable_mp(this, &ScriptEditor::_file_removed));
script_list->connect("item_selected", callable_mp(this, &ScriptEditor::_script_selected));
@@ -1619,7 +1641,7 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) {
}
if (script->is_built_in() && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed
- _close_tab(i);
+ _close_tab(i, false);
i--;
}
}
@@ -1926,20 +1948,7 @@ void ScriptEditor::_update_script_names() {
// to update original path to previously edited resource.
se->set_meta("_edit_res_path", path);
}
- bool built_in = !path.is_resource_file();
- String name;
-
- if (built_in) {
- name = path.get_file();
- const String &resource_name = se->get_edited_resource()->get_name();
- if (resource_name != "") {
- // If the built-in script has a custom resource name defined,
- // display the built-in script name as follows: `ResourceName (scene_file.tscn)`
- name = vformat("%s (%s)", resource_name, name.substr(0, name.find("::", 0)));
- }
- } else {
- name = se->get_name();
- }
+ String name = se->get_name();
_ScriptEditorItemData sd;
sd.icon = icon;
@@ -2403,7 +2412,17 @@ void ScriptEditor::save_current_script() {
}
}
- editor->save_resource(resource);
+ if (resource->is_built_in()) {
+ // If built-in script, save the scene instead.
+ const String scene_path = resource->get_path().get_slice("::", 0);
+ if (!scene_path.is_empty()) {
+ Vector<String> scene_to_save;
+ scene_to_save.push_back(scene_path);
+ editor->save_scene_list(scene_to_save);
+ }
+ } else {
+ editor->save_resource(resource);
+ }
if (script != nullptr) {
const Vector<DocData::ClassDoc> &documentations = script->get_documentation();
@@ -2416,6 +2435,8 @@ void ScriptEditor::save_current_script() {
}
void ScriptEditor::save_all_scripts() {
+ Vector<String> scenes_to_save;
+
for (int i = 0; i < tab_container->get_child_count(); i++) {
ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
if (!se) {
@@ -2474,9 +2495,19 @@ void ScriptEditor::save_all_scripts() {
update_doc(doc.name);
}
}
+ } else {
+ // For built-in scripts, save their scenes instead.
+ const String scene_path = edited_res->get_path().get_slice("::", 0);
+ if (!scenes_to_save.has(scene_path)) {
+ scenes_to_save.push_back(scene_path);
+ }
}
}
+ if (!scenes_to_save.is_empty()) {
+ editor->save_scene_list(scenes_to_save);
+ }
+
_update_script_names();
EditorFileSystem::get_singleton()->update_script_classes();
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 2b0bdfd109..0adeca031e 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -365,6 +365,7 @@ class ScriptEditor : public PanelContainer {
void _add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args);
void _res_saved_callback(const Ref<Resource> &p_res);
+ void _scene_saved_callback(const String &p_path);
bool open_textfile_after_create = true;
bool trim_trailing_whitespace_on_save;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 24cdc06d78..a655420d27 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -375,18 +375,21 @@ void ScriptTextEditor::ensure_focus() {
String ScriptTextEditor::get_name() {
String name;
- if (!script->is_built_in()) {
- name = script->get_path().get_file();
- if (is_unsaved()) {
- if (script->get_path().is_empty()) {
- name = TTR("[unsaved]");
- }
- name += "(*)";
+ name = script->get_path().get_file();
+ if (name.is_empty()) {
+ // This appears for newly created built-in scripts before saving the scene.
+ name = TTR("[unsaved]");
+ } else if (script->is_built_in()) {
+ const String &script_name = script->get_name();
+ if (script_name != "") {
+ // If the built-in script has a custom resource name defined,
+ // display the built-in script name as follows: `ResourceName (scene_file.tscn)`
+ name = vformat("%s (%s)", script_name, name.get_slice("::", 0));
}
- } else if (script->get_name() != "") {
- name = script->get_name();
- } else {
- name = script->get_class() + "(" + itos(script->get_instance_id()) + ")";
+ }
+
+ if (is_unsaved()) {
+ name += "(*)";
}
return name;
diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp
index 91c5e96f08..1c7f319280 100644
--- a/editor/plugins/style_box_editor_plugin.cpp
+++ b/editor/plugins/style_box_editor_plugin.cpp
@@ -44,13 +44,6 @@ void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) {
add_custom_control(preview);
}
-bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, bool p_wide) {
- return false; //do not want
-}
-
-void EditorInspectorPluginStyleBox::parse_end() {
-}
-
void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) {
if (stylebox.is_valid()) {
stylebox->disconnect("changed", callable_mp(this, &StyleBoxPreview::_sb_changed));
diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h
index 8ca348bd80..d82e5ab05e 100644
--- a/editor/plugins/style_box_editor_plugin.h
+++ b/editor/plugins/style_box_editor_plugin.h
@@ -61,8 +61,6 @@ class EditorInspectorPluginStyleBox : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
- virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
};
class StyleBoxEditorPlugin : public EditorPlugin {
diff --git a/editor/plugins/text_control_editor_plugin.cpp b/editor/plugins/text_control_editor_plugin.cpp
new file mode 100644
index 0000000000..c878c83430
--- /dev/null
+++ b/editor/plugins/text_control_editor_plugin.cpp
@@ -0,0 +1,375 @@
+/*************************************************************************/
+/* text_control_editor_plugin.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 "text_control_editor_plugin.h"
+
+#include "editor/editor_scale.h"
+
+void TextControlEditor::_notification(int p_notification) {
+ switch (p_notification) {
+ case NOTIFICATION_ENTER_TREE: {
+ if (!EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) {
+ EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts), make_binds(""));
+ }
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ clear_formatting->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));
+ } break;
+ case NOTIFICATION_EXIT_TREE: {
+ if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) {
+ EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts));
+ }
+ } break;
+ default:
+ break;
+ }
+}
+
+void TextControlEditor::_find_resources(EditorFileSystemDirectory *p_dir) {
+ for (int i = 0; i < p_dir->get_subdir_count(); i++) {
+ _find_resources(p_dir->get_subdir(i));
+ }
+
+ for (int i = 0; i < p_dir->get_file_count(); i++) {
+ if (p_dir->get_file_type(i) == "FontData") {
+ Ref<FontData> fd = ResourceLoader::load(p_dir->get_file_path(i));
+ if (fd.is_valid()) {
+ String name = fd->get_font_name();
+ String sty = fd->get_font_style_name();
+ if (sty.is_empty()) {
+ sty = "Default";
+ }
+ fonts[name][sty] = p_dir->get_file_path(i);
+ }
+ }
+ }
+}
+
+void TextControlEditor::_reload_fonts(const String &p_path) {
+ fonts.clear();
+ _find_resources(EditorFileSystem::get_singleton()->get_filesystem());
+ _update_control();
+}
+
+void TextControlEditor::_update_fonts_menu() {
+ font_list->clear();
+ font_list->add_item(TTR("[Theme Default]"), FONT_INFO_THEME_DEFAULT);
+ if (custom_font.is_valid()) {
+ font_list->add_item(TTR("[Custom Font]"), FONT_INFO_USER_CUSTOM);
+ }
+
+ int id = FONT_INFO_ID;
+ for (Map<String, Map<String, String>>::Element *E = fonts.front(); E; E = E->next()) {
+ font_list->add_item(E->key(), id++);
+ }
+
+ if (font_list->get_item_count() > 1) {
+ font_list->show();
+ } else {
+ font_list->hide();
+ }
+}
+
+void TextControlEditor::_update_styles_menu() {
+ font_style_list->clear();
+ if ((font_list->get_selected_id() >= FONT_INFO_ID)) {
+ const String &name = font_list->get_item_text(font_list->get_selected());
+ for (Map<String, String>::Element *E = fonts[name].front(); E; E = E->next()) {
+ font_style_list->add_item(E->key());
+ }
+ } else {
+ font_style_list->add_item("Default");
+ }
+
+ if (font_style_list->get_item_count() > 1) {
+ font_style_list->show();
+ } else {
+ font_style_list->hide();
+ }
+}
+
+void TextControlEditor::_update_control() {
+ if (edited_control) {
+ // Get override names.
+ if (edited_control->is_class("RichTextLabel")) {
+ edited_color = "default_color";
+ edited_font = "normal_font";
+ edited_font_size = "normal_font_size";
+ } else {
+ edited_color = "font_color";
+ edited_font = "font";
+ edited_font_size = "font_size";
+ }
+
+ // Get font override.
+ Ref<Font> font;
+ if (edited_control->has_theme_font_override(edited_font)) {
+ font = edited_control->get_theme_font(edited_font);
+ }
+ if (font.is_valid()) {
+ if (font->get_data_count() != 1) {
+ // Composite font, save it to "custom_font" to allow undoing font change.
+ custom_font = font;
+ _update_fonts_menu();
+ font_list->select(FONT_INFO_USER_CUSTOM);
+ _update_styles_menu();
+ font_style_list->select(0);
+ } else {
+ // Single face font, search for the font with matching name and style.
+ String name = font->get_data(0)->get_font_name();
+ String style = font->get_data(0)->get_font_style_name();
+ if (fonts.has(name) && fonts[name].has(style)) {
+ _update_fonts_menu();
+ for (int i = 0; i < font_list->get_item_count(); i++) {
+ if (font_list->get_item_text(i) == name) {
+ font_list->select(i);
+ break;
+ }
+ }
+ _update_styles_menu();
+ for (int i = 0; i < font_style_list->get_item_count(); i++) {
+ if (font_style_list->get_item_text(i) == style) {
+ font_style_list->select(i);
+ break;
+ }
+ }
+ } else {
+ // Unknown font, save it to "custom_font" to allow undoing font change.
+ custom_font = font;
+ _update_fonts_menu();
+ font_list->select(FONT_INFO_USER_CUSTOM);
+ _update_styles_menu();
+ font_style_list->select(0);
+ }
+ }
+ } else {
+ // No font override, select "Theme Default".
+ _update_fonts_menu();
+ font_list->select(FONT_INFO_THEME_DEFAULT);
+ _update_styles_menu();
+ font_style_list->select(0);
+ }
+
+ // Get other theme overrides.
+ font_size_list->set_value(edited_control->get_theme_font_size(edited_font_size));
+ outline_size_list->set_value(edited_control->get_theme_constant("outline_size"));
+
+ font_color_picker->set_pick_color(edited_control->get_theme_color(edited_color));
+ outline_color_picker->set_pick_color(edited_control->get_theme_color("font_outline_color"));
+ }
+}
+
+void TextControlEditor::_font_selected(int p_id) {
+ _update_styles_menu();
+ _set_font();
+}
+
+void TextControlEditor::_font_style_selected(int p_id) {
+ _set_font();
+}
+
+void TextControlEditor::_set_font() {
+ if (edited_control) {
+ if (font_list->get_selected_id() == FONT_INFO_THEME_DEFAULT) {
+ // Remove font override.
+ edited_control->remove_theme_font_override(edited_font);
+ return;
+ } else if (font_list->get_selected_id() == FONT_INFO_USER_CUSTOM) {
+ // Restore "custom_font".
+ edited_control->add_theme_font_override(edited_font, custom_font);
+ return;
+ } else {
+ // Load new font resource using selected name and style.
+ String name = font_list->get_item_text(font_list->get_selected());
+ String sty = font_style_list->get_item_text(font_style_list->get_selected());
+ if (sty.is_empty()) {
+ sty = "Default";
+ }
+ if (fonts.has(name)) {
+ Ref<FontData> fd = ResourceLoader::load(fonts[name][sty]);
+ if (fd.is_valid()) {
+ Ref<Font> f;
+ f.instantiate();
+ f->add_data(fd);
+ edited_control->add_theme_font_override(edited_font, f);
+ }
+ }
+ }
+ }
+}
+
+void TextControlEditor::_font_size_selected(double p_size) {
+ if (edited_control) {
+ edited_control->add_theme_font_size_override(edited_font_size, p_size);
+ }
+}
+
+void TextControlEditor::_outline_size_selected(double p_size) {
+ if (edited_control) {
+ edited_control->add_theme_constant_override("outline_size", p_size);
+ }
+}
+
+void TextControlEditor::_font_color_changed(const Color &p_color) {
+ if (edited_control) {
+ edited_control->add_theme_color_override(edited_color, p_color);
+ }
+}
+
+void TextControlEditor::_outline_color_changed(const Color &p_color) {
+ if (edited_control) {
+ edited_control->add_theme_color_override("font_outline_color", p_color);
+ }
+}
+
+void TextControlEditor::_clear_formatting() {
+ if (edited_control) {
+ edited_control->begin_bulk_theme_override();
+ edited_control->remove_theme_font_override(edited_font);
+ edited_control->remove_theme_font_size_override(edited_font_size);
+ edited_control->remove_theme_color_override(edited_color);
+ edited_control->remove_theme_color_override("font_outline_color");
+ edited_control->remove_theme_constant_override("outline_size");
+ edited_control->end_bulk_theme_override();
+ _update_control();
+ }
+}
+
+void TextControlEditor::edit(Object *p_object) {
+ Control *ctrl = Object::cast_to<Control>(p_object);
+ if (!ctrl) {
+ edited_control = nullptr;
+ custom_font = Ref<Font>();
+ } else {
+ edited_control = ctrl;
+ custom_font = Ref<Font>();
+ _update_control();
+ }
+}
+
+bool TextControlEditor::handles(Object *p_object) const {
+ Control *ctrl = Object::cast_to<Control>(p_object);
+ if (!ctrl) {
+ return false;
+ } else {
+ bool valid = false;
+ ctrl->get("text", &valid);
+ return valid;
+ }
+}
+
+TextControlEditor::TextControlEditor() {
+ add_child(memnew(VSeparator));
+
+ font_list = memnew(OptionButton);
+ font_list->set_flat(true);
+ font_list->set_tooltip(TTR("Font"));
+ add_child(font_list);
+ font_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_selected));
+
+ font_style_list = memnew(OptionButton);
+ font_style_list->set_flat(true);
+ font_style_list->set_tooltip(TTR("Font style"));
+ font_style_list->set_toggle_mode(true);
+ add_child(font_style_list);
+ font_style_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_style_selected));
+
+ font_size_list = memnew(SpinBox);
+ font_size_list->set_tooltip(TTR("Font Size"));
+ font_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);
+ font_size_list->set_min(6);
+ font_size_list->set_step(1);
+ font_size_list->set_max(96);
+ font_size_list->get_line_edit()->set_flat(true);
+ add_child(font_size_list);
+ font_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_font_size_selected));
+
+ font_color_picker = memnew(ColorPickerButton);
+ font_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
+ font_color_picker->set_flat(true);
+ font_color_picker->set_tooltip(TTR("Text Color"));
+ add_child(font_color_picker);
+ font_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_font_color_changed));
+
+ add_child(memnew(VSeparator));
+
+ outline_size_list = memnew(SpinBox);
+ outline_size_list->set_tooltip(TTR("Outline Size"));
+ outline_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2);
+ outline_size_list->set_min(0);
+ outline_size_list->set_step(1);
+ outline_size_list->set_max(96);
+ outline_size_list->get_line_edit()->set_flat(true);
+ add_child(outline_size_list);
+ outline_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_outline_size_selected));
+
+ outline_color_picker = memnew(ColorPickerButton);
+ outline_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE);
+ outline_color_picker->set_flat(true);
+ outline_color_picker->set_tooltip(TTR("Outline Color"));
+ add_child(outline_color_picker);
+ outline_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_outline_color_changed));
+
+ add_child(memnew(VSeparator));
+
+ clear_formatting = memnew(Button);
+ clear_formatting->set_flat(true);
+ clear_formatting->set_tooltip(TTR("Clear Formatting"));
+ add_child(clear_formatting);
+ clear_formatting->connect("pressed", callable_mp(this, &TextControlEditor::_clear_formatting));
+}
+
+/*************************************************************************/
+
+void TextControlEditorPlugin::edit(Object *p_object) {
+ text_ctl_editor->edit(p_object);
+}
+
+bool TextControlEditorPlugin::handles(Object *p_object) const {
+ return text_ctl_editor->handles(p_object);
+}
+
+void TextControlEditorPlugin::make_visible(bool p_visible) {
+ if (p_visible) {
+ text_ctl_editor->show();
+ } else {
+ text_ctl_editor->hide();
+ text_ctl_editor->edit(nullptr);
+ }
+}
+
+TextControlEditorPlugin::TextControlEditorPlugin(EditorNode *p_node) {
+ editor = p_node;
+ text_ctl_editor = memnew(TextControlEditor);
+ CanvasItemEditor::get_singleton()->add_control_to_menu_panel(text_ctl_editor);
+
+ text_ctl_editor->hide();
+}
diff --git a/editor/plugins/text_control_editor_plugin.h b/editor/plugins/text_control_editor_plugin.h
new file mode 100644
index 0000000000..7f4aa3754c
--- /dev/null
+++ b/editor/plugins/text_control_editor_plugin.h
@@ -0,0 +1,119 @@
+/*************************************************************************/
+/* text_control_editor_plugin.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 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 TEXT_CONTROL_EDITOR_PLUGIN_H
+#define TEXT_CONTROL_EDITOR_PLUGIN_H
+
+#include "canvas_item_editor_plugin.h"
+#include "editor/editor_file_system.h"
+#include "editor/editor_inspector.h"
+#include "editor/editor_node.h"
+#include "editor/editor_plugin.h"
+#include "scene/gui/color_rect.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/option_button.h"
+#include "scene/gui/popup_menu.h"
+
+/*************************************************************************/
+
+class TextControlEditor : public HBoxContainer {
+ GDCLASS(TextControlEditor, HBoxContainer);
+
+ enum FontInfoID {
+ FONT_INFO_THEME_DEFAULT = 0,
+ FONT_INFO_USER_CUSTOM = 1,
+ FONT_INFO_ID = 100,
+ };
+
+ Map<String, Map<String, String>> fonts;
+
+ OptionButton *font_list = nullptr;
+ SpinBox *font_size_list = nullptr;
+ OptionButton *font_style_list = nullptr;
+ ColorPickerButton *font_color_picker = nullptr;
+ SpinBox *outline_size_list = nullptr;
+ ColorPickerButton *outline_color_picker = nullptr;
+ Button *clear_formatting = nullptr;
+
+ Control *edited_control = nullptr;
+ String edited_color;
+ String edited_font;
+ String edited_font_size;
+ Ref<Font> custom_font;
+
+protected:
+ void _notification(int p_notification);
+ static void _bind_methods(){};
+
+ void _find_resources(EditorFileSystemDirectory *p_dir);
+ void _reload_fonts(const String &p_path);
+
+ void _update_fonts_menu();
+ void _update_styles_menu();
+ void _update_control();
+
+ void _font_selected(int p_id);
+ void _font_style_selected(int p_id);
+ void _set_font();
+
+ void _font_size_selected(double p_size);
+ void _outline_size_selected(double p_size);
+
+ void _font_color_changed(const Color &p_color);
+ void _outline_color_changed(const Color &p_color);
+
+ void _clear_formatting();
+
+public:
+ void edit(Object *p_object);
+ bool handles(Object *p_object) const;
+
+ TextControlEditor();
+};
+
+/*************************************************************************/
+
+class TextControlEditorPlugin : public EditorPlugin {
+ GDCLASS(TextControlEditorPlugin, EditorPlugin);
+
+ TextControlEditor *text_ctl_editor;
+ EditorNode *editor;
+
+public:
+ virtual String get_name() const override { return "TextControlFontEditor"; }
+ bool has_main_screen() const override { return false; }
+ virtual void edit(Object *p_object) override;
+ virtual bool handles(Object *p_object) const override;
+ virtual void make_visible(bool p_visible) override;
+
+ TextControlEditorPlugin(EditorNode *p_node);
+};
+
+#endif // TEXT_CONTROL_EDITOR_PLUGIN_H
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index 3b45f32927..8186c2c84c 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -65,18 +65,21 @@ void TextEditor::_load_theme_settings() {
String TextEditor::get_name() {
String name;
- if (!text_file->is_built_in()) {
- name = text_file->get_path().get_file();
- if (is_unsaved()) {
- if (text_file->get_path().is_empty()) {
- name = TTR("[unsaved]");
- }
- name += "(*)";
+ name = text_file->get_path().get_file();
+ if (name.is_empty()) {
+ // This appears for newly created built-in text_files before saving the scene.
+ name = TTR("[unsaved]");
+ } else if (text_file->is_built_in()) {
+ const String &text_file_name = text_file->get_name();
+ if (text_file_name != "") {
+ // If the built-in text_file has a custom resource name defined,
+ // display the built-in text_file name as follows: `ResourceName (scene_file.tscn)`
+ name = vformat("%s (%s)", text_file_name, name.get_slice("::", 0));
}
- } else if (text_file->get_name() != "") {
- name = text_file->get_name();
- } else {
- name = text_file->get_class() + "(" + itos(text_file->get_instance_id()) + ")";
+ }
+
+ if (is_unsaved()) {
+ name += "(*)";
}
return name;
diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp
index bd1923f4ab..b4e394a1c0 100644
--- a/editor/plugins/texture_3d_editor_plugin.cpp
+++ b/editor/plugins/texture_3d_editor_plugin.cpp
@@ -173,7 +173,7 @@ Texture3DEditor::Texture3DEditor() {
info->set_v_grow_direction(GROW_DIRECTION_BEGIN);
info->add_theme_color_override("font_color", Color(1, 1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5));
- info->add_theme_constant_override("shadow_as_outline", 1);
+ info->add_theme_constant_override("shadow_outline_size", 1);
info->add_theme_constant_override("shadow_offset_x", 2);
info->add_theme_constant_override("shadow_offset_y", 2);
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index b9ec6bf5ab..e25b0270b4 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -101,7 +101,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) {
metadata_label->add_theme_color_override("font_outline_color", Color::named("black"));
metadata_label->add_theme_constant_override("outline_size", 2 * EDSCALE);
- metadata_label->add_theme_constant_override("shadow_as_outline", 1);
+ metadata_label->add_theme_constant_override("shadow_outline_size", 1);
metadata_label->set_h_size_flags(Control::SIZE_SHRINK_END);
metadata_label->set_v_size_flags(Control::SIZE_SHRINK_END);
diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp
index 424e018a47..ee62138d12 100644
--- a/editor/plugins/texture_layered_editor_plugin.cpp
+++ b/editor/plugins/texture_layered_editor_plugin.cpp
@@ -249,7 +249,7 @@ TextureLayeredEditor::TextureLayeredEditor() {
info->set_v_grow_direction(GROW_DIRECTION_BEGIN);
info->add_theme_color_override("font_color", Color(1, 1, 1, 1));
info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5));
- info->add_theme_constant_override("shadow_as_outline", 1);
+ info->add_theme_constant_override("shadow_outline_size", 1);
info->add_theme_constant_override("shadow_offset_x", 2);
info->add_theme_constant_override("shadow_offset_y", 2);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 10a9b2bb10..f87b1c2be1 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -4527,6 +4527,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("MultiplyByAxisAngle", "Particles", "Transform", "VisualShaderNodeParticleMultiplyByAxisAngle", "A node for help to multiply a position input vector by rotation using specific axis. Intended to work with emitters.", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT | TYPE_FLAGS_PROCESS | TYPE_FLAGS_COLLIDE, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("BoxEmitter", "Particles", "Emitters", "VisualShaderNodeParticleBoxEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
+ add_options.push_back(AddOption("MeshEmitter", "Particles", "Emitters", "VisualShaderNodeParticleMeshEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("RingEmitter", "Particles", "Emitters", "VisualShaderNodeParticleRingEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
add_options.push_back(AddOption("SphereEmitter", "Particles", "Emitters", "VisualShaderNodeParticleSphereEmitter", "", -1, VisualShaderNode::PORT_TYPE_VECTOR, TYPE_FLAGS_EMIT, Shader::MODE_PARTICLES));
@@ -5186,11 +5187,7 @@ EditorPropertyShaderMode::EditorPropertyShaderMode() {
}
bool EditorInspectorShaderModePlugin::can_handle(Object *p_object) {
- return true; //can handle everything
-}
-
-void EditorInspectorShaderModePlugin::parse_begin(Object *p_object) {
- //do none
+ return true; // Can handle everything.
}
bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
@@ -5203,11 +5200,7 @@ bool EditorInspectorShaderModePlugin::parse_property(Object *p_object, const Var
return true;
}
- return false; //can be overridden, although it will most likely be last anyway
-}
-
-void EditorInspectorShaderModePlugin::parse_end() {
- //do none
+ return false;
}
//////////////////////////////////
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index c4a392469b..74ccda3c9a 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -523,9 +523,7 @@ class EditorInspectorShaderModePlugin : public EditorInspectorPlugin {
public:
virtual bool can_handle(Object *p_object) override;
- virtual void parse_begin(Object *p_object) override;
virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide = false) override;
- virtual void parse_end() override;
};
class VisualShaderNodePortPreview : public Control {
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 2792c193d9..f5b70504fa 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -461,7 +461,7 @@ String RenameDialog::_substitute(const String &subject, const Node *node, int co
void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) {
RenameDialog *self = (RenameDialog *)p_self;
- String source_file(p_file);
+ String source_file = String::utf8(p_file);
// Only show first error that is related to "regex"
if (self->has_errors || source_file.find("regex") < 0) {
@@ -470,9 +470,9 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *
String err_str;
if (p_errorexp && p_errorexp[0]) {
- err_str = p_errorexp;
+ err_str = String::utf8(p_errorexp);
} else {
- err_str = p_error;
+ err_str = String::utf8(p_error);
}
self->has_errors = true;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 6da3e78da9..921befbb6b 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -47,6 +47,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "editor/shader_create_dialog.h"
#include "scene/main/window.h"
+#include "scene/property_utils.h"
#include "scene/resources/packed_scene.h"
#include "servers/display_server.h"
#include "servers/rendering_server.h"
@@ -3132,7 +3133,9 @@ void SceneTreeDock::_clear_clipboard() {
void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) {
List<PropertyInfo> props;
p_node->get_property_list(&props);
- bool is_instantiated = EditorPropertyRevert::may_node_be_in_instance(p_node);
+
+ Vector<SceneState::PackState> states_stack;
+ bool states_stack_ready = false;
for (const PropertyInfo &E : props) {
if (!(E.usage & PROPERTY_USAGE_STORAGE)) {
@@ -3143,13 +3146,14 @@ void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap)
if (v.is_ref()) {
RES res = v;
if (res.is_valid()) {
- if (is_instantiated) {
- Variant orig;
- if (EditorPropertyRevert::get_instantiated_node_original_property(p_node, E.name, orig)) {
- if (!EditorPropertyRevert::is_node_property_different(p_node, v, orig)) {
- continue;
- }
- }
+ if (!states_stack_ready) {
+ states_stack = PropertyUtils::get_node_states_stack(p_node);
+ states_stack_ready = true;
+ }
+
+ Variant orig = PropertyUtils::get_property_default_value(p_node, E.name, &states_stack);
+ if (!PropertyUtils::is_property_value_different(v, orig)) {
+ continue;
}
if (res->is_built_in() && !r_remap.has(res)) {