summaryrefslogtreecommitdiff
path: root/editor
diff options
context:
space:
mode:
Diffstat (limited to 'editor')
-rw-r--r--editor/action_map_editor.cpp47
-rw-r--r--editor/action_map_editor.h2
-rw-r--r--editor/doc_tools.cpp167
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/editor_resource_picker.cpp20
-rw-r--r--editor/editor_resource_picker.h4
-rw-r--r--editor/editor_settings.cpp16
-rw-r--r--editor/import/resource_importer_obj.h3
-rw-r--r--editor/import/resource_importer_texture_atlas.cpp4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp75
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.h18
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp32
-rw-r--r--editor/plugins/script_editor_plugin.cpp42
-rw-r--r--editor/plugins/script_editor_plugin.h2
14 files changed, 249 insertions, 185 deletions
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 6789b5be00..38db48a4d4 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -120,8 +120,8 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
physical_key_checkbox->set_visible(show_phys_key);
additional_options_container->show();
- // Update selected item in input list for keys, joybuttons and joyaxis only (since the mouse cannot be "listened" for).
- if (k.is_valid() || joyb.is_valid() || joym.is_valid()) {
+ // Update selected item in input list.
+ if (k.is_valid() || joyb.is_valid() || joym.is_valid() || mb.is_valid()) {
TreeItem *category = input_list_tree->get_root()->get_first_child();
while (category) {
TreeItem *input_item = category->get_first_child();
@@ -134,13 +134,14 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
}
// If event type matches input types of this category.
- if ((k.is_valid() && input_type == INPUT_KEY) || (joyb.is_valid() && input_type == INPUT_JOY_BUTTON) || (joym.is_valid() && input_type == INPUT_JOY_MOTION)) {
+ if ((k.is_valid() && input_type == INPUT_KEY) || (joyb.is_valid() && input_type == INPUT_JOY_BUTTON) || (joym.is_valid() && input_type == INPUT_JOY_MOTION) || (mb.is_valid() && input_type == INPUT_MOUSE_BUTTON)) {
// Loop through all items of this category until one matches.
while (input_item) {
bool key_match = k.is_valid() && (Variant(k->get_keycode()) == input_item->get_meta("__keycode") || Variant(k->get_physical_keycode()) == input_item->get_meta("__keycode"));
bool joyb_match = joyb.is_valid() && Variant(joyb->get_button_index()) == input_item->get_meta("__index");
bool joym_match = joym.is_valid() && Variant(joym->get_axis()) == input_item->get_meta("__axis") && joym->get_axis_value() == (float)input_item->get_meta("__value");
- if (key_match || joyb_match || joym_match) {
+ bool mb_match = mb.is_valid() && Variant(mb->get_button_index()) == input_item->get_meta("__index");
+ if (key_match || joyb_match || joym_match || mb_match) {
category->set_collapsed(false);
input_item->select(0);
input_list_tree->ensure_cursor_is_visible();
@@ -165,7 +166,6 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
if (allowed_input_types & INPUT_KEY) {
strings.append(TTR("Key"));
}
- // We don't check for INPUT_MOUSE_BUTTON since it is ignored in the "Listen Window Input" method.
if (allowed_input_types & INPUT_JOY_BUTTON) {
strings.append(TTR("Joypad Button"));
@@ -173,7 +173,9 @@ void InputEventConfigurationDialog::_set_event(const Ref<InputEvent> &p_event) {
if (allowed_input_types & INPUT_JOY_MOTION) {
strings.append(TTR("Joypad Axis"));
}
-
+ if (allowed_input_types & INPUT_MOUSE_BUTTON) {
+ strings.append(TTR("Mouse Button in area below"));
+ }
if (strings.size() == 0) {
text = TTR("Input Event dialog has been misconfigured: No input types are allowed.");
event_as_text->set_text(text);
@@ -214,12 +216,21 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &
return;
}
- // Ignore mouse
- Ref<InputEventMouse> m = p_event;
- if (m.is_valid()) {
+ // Ignore mouse motion
+ Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
return;
}
+ // Ignore mouse button if not in the detection rect
+ Ref<InputEventMouseButton> mb = p_event;
+ if (mb.is_valid()) {
+ Rect2 r = mouse_detection_rect->get_rect();
+ if (!r.has_point(mouse_detection_rect->get_local_mouse_position() + r.get_position())) {
+ return;
+ }
+ }
+
// Check what the type is and if it is allowed.
Ref<InputEventKey> k = p_event;
Ref<InputEventJoypadButton> joyb = p_event;
@@ -227,6 +238,7 @@ void InputEventConfigurationDialog::_listen_window_input(const Ref<InputEvent> &
int type = k.is_valid() ? INPUT_KEY : joyb.is_valid() ? INPUT_JOY_BUTTON :
joym.is_valid() ? INPUT_JOY_MOTION :
+ mb.is_valid() ? INPUT_MOUSE_BUTTON :
0;
if (!(allowed_input_types & type)) {
@@ -537,6 +549,8 @@ void InputEventConfigurationDialog::_notification(int p_what) {
icon_cache.joypad_button = get_theme_icon(SNAME("JoyButton"), SNAME("EditorIcons"));
icon_cache.joypad_axis = get_theme_icon(SNAME("JoyAxis"), SNAME("EditorIcons"));
+ mouse_detection_rect->set_color(get_theme_color(SNAME("dark_color_2"), SNAME("Editor")));
+
_update_input_list();
} break;
default:
@@ -575,7 +589,7 @@ void InputEventConfigurationDialog::set_allowed_input_types(int p_type_masks) {
}
InputEventConfigurationDialog::InputEventConfigurationDialog() {
- allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION;
+ allowed_input_types = INPUT_KEY | INPUT_MOUSE_BUTTON | INPUT_JOY_BUTTON | INPUT_JOY_MOTION | INPUT_MOUSE_BUTTON;
set_title(TTR("Event Configuration"));
set_min_size(Size2i(550 * EDSCALE, 0)); // Min width
@@ -590,12 +604,17 @@ InputEventConfigurationDialog::InputEventConfigurationDialog() {
tab_container->connect("tab_selected", callable_mp(this, &InputEventConfigurationDialog::_tab_selected));
main_vbox->add_child(tab_container);
- CenterContainer *cc = memnew(CenterContainer);
- cc->set_name(TTR("Listen for Input"));
+ // Listen to input tab
+ VBoxContainer *vb = memnew(VBoxContainer);
+ vb->set_name(TTR("Listen for Input"));
event_as_text = memnew(Label);
event_as_text->set_align(Label::ALIGN_CENTER);
- cc->add_child(event_as_text);
- tab_container->add_child(cc);
+ vb->add_child(event_as_text);
+ // Mouse button detection rect (Mouse button event outside this ColorRect will be ignored)
+ mouse_detection_rect = memnew(ColorRect);
+ mouse_detection_rect->set_v_size_flags(Control::SIZE_EXPAND_FILL);
+ vb->add_child(mouse_detection_rect);
+ tab_container->add_child(vb);
// List of all input options to manually select from.
diff --git a/editor/action_map_editor.h b/editor/action_map_editor.h
index aff3e6e957..e55cab3510 100644
--- a/editor/action_map_editor.h
+++ b/editor/action_map_editor.h
@@ -32,6 +32,7 @@
#define ACTION_MAP_EDITOR_H
#include "editor/editor_data.h"
+#include <scene/gui/color_rect.h>
// Confirmation Dialog used when configuring an input event.
// Separate from ActionMapEditor for code cleanliness and separation of responsibilities.
@@ -60,6 +61,7 @@ private:
// Listening for input
Label *event_as_text;
+ ColorRect *mouse_detection_rect;
// List of All Key/Mouse/Joypad input options.
int allowed_input_types;
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index d04875f188..ec162231e9 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -1173,6 +1173,59 @@ static void _write_string(FileAccess *f, int p_tablevel, const String &p_string)
f->store_string(tab + p_string + "\n");
}
+static void _write_method_doc(FileAccess *f, const String &p_name, Vector<DocData::MethodDoc> &p_method_docs) {
+ if (!p_method_docs.is_empty()) {
+ p_method_docs.sort();
+ _write_string(f, 1, "<" + p_name + "s>");
+ for (int i = 0; i < p_method_docs.size(); i++) {
+ const DocData::MethodDoc &m = p_method_docs[i];
+
+ String qualifiers;
+ if (m.qualifiers != "") {
+ qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\"";
+ }
+
+ _write_string(f, 2, "<" + p_name + " name=\"" + m.name.xml_escape() + "\"" + qualifiers + ">");
+
+ if (m.return_type != "") {
+ String enum_text;
+ if (m.return_enum != String()) {
+ enum_text = " enum=\"" + m.return_enum + "\"";
+ }
+ _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + " />");
+ }
+ if (m.errors_returned.size() > 0) {
+ for (int j = 0; j < m.errors_returned.size(); j++) {
+ _write_string(f, 3, "<returns_error number=\"" + itos(m.errors_returned[j]) + "\"/>");
+ }
+ }
+
+ for (int j = 0; j < m.arguments.size(); j++) {
+ const DocData::ArgumentDoc &a = m.arguments[j];
+
+ String enum_text;
+ if (a.enumeration != String()) {
+ enum_text = " enum=\"" + a.enumeration + "\"";
+ }
+
+ if (a.default_value != "") {
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\" />");
+ } else {
+ _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " />");
+ }
+ }
+
+ _write_string(f, 3, "<description>");
+ _write_string(f, 4, m.description.strip_edges().xml_escape());
+ _write_string(f, 3, "</description>");
+
+ _write_string(f, 2, "</" + p_name + ">");
+ }
+
+ _write_string(f, 1, "</" + p_name + "s>");
+ }
+}
+
Error DocTools::save_classes(const String &p_default_path, const Map<String, String> &p_class_path) {
for (Map<String, DocData::ClassDoc>::Element *E = class_list.front(); E; E = E->next()) {
DocData::ClassDoc &c = E->get();
@@ -1216,58 +1269,9 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
}
_write_string(f, 1, "</tutorials>");
- _write_string(f, 1, "<methods>");
-
- c.methods.sort();
-
- for (int i = 0; i < c.methods.size(); i++) {
- const DocData::MethodDoc &m = c.methods[i];
-
- String qualifiers;
- if (m.qualifiers != "") {
- qualifiers += " qualifiers=\"" + m.qualifiers.xml_escape() + "\"";
- }
-
- _write_string(f, 2, "<method name=\"" + m.name.xml_escape() + "\"" + qualifiers + ">");
+ _write_method_doc(f, "method", c.methods);
- if (m.return_type != "") {
- String enum_text;
- if (m.return_enum != String()) {
- enum_text = " enum=\"" + m.return_enum + "\"";
- }
- _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + " />");
- }
- if (m.errors_returned.size() > 0) {
- for (int j = 0; j < m.errors_returned.size(); j++) {
- _write_string(f, 3, "<returns_error number=\"" + itos(m.errors_returned[j]) + "\"/>");
- }
- }
-
- for (int j = 0; j < m.arguments.size(); j++) {
- const DocData::ArgumentDoc &a = m.arguments[j];
-
- String enum_text;
- if (a.enumeration != String()) {
- enum_text = " enum=\"" + a.enumeration + "\"";
- }
-
- if (a.default_value != "") {
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " default=\"" + a.default_value.xml_escape(true) + "\" />");
- } else {
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\"" + enum_text + " />");
- }
- }
-
- _write_string(f, 3, "<description>");
- _write_string(f, 4, m.description.strip_edges().xml_escape());
- _write_string(f, 3, "</description>");
-
- _write_string(f, 2, "</method>");
- }
-
- _write_string(f, 1, "</methods>");
-
- if (c.properties.size()) {
+ if (!c.properties.is_empty()) {
_write_string(f, 1, "<members>");
c.properties.sort();
@@ -1294,52 +1298,33 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
_write_string(f, 1, "</members>");
}
- if (c.signals.size()) {
- c.signals.sort();
-
- _write_string(f, 1, "<signals>");
- for (int i = 0; i < c.signals.size(); i++) {
- const DocData::MethodDoc &m = c.signals[i];
- _write_string(f, 2, "<signal name=\"" + m.name + "\">");
- for (int j = 0; j < m.arguments.size(); j++) {
- const DocData::ArgumentDoc &a = m.arguments[j];
- _write_string(f, 3, "<argument index=\"" + itos(j) + "\" name=\"" + a.name.xml_escape() + "\" type=\"" + a.type.xml_escape() + "\" />");
- }
-
- _write_string(f, 3, "<description>");
- _write_string(f, 4, m.description.strip_edges().xml_escape());
- _write_string(f, 3, "</description>");
-
- _write_string(f, 2, "</signal>");
- }
-
- _write_string(f, 1, "</signals>");
- }
-
- _write_string(f, 1, "<constants>");
+ _write_method_doc(f, "signal", c.signals);
- for (int i = 0; i < c.constants.size(); i++) {
- const DocData::ConstantDoc &k = c.constants[i];
- if (k.is_value_valid) {
- if (k.enumeration != String()) {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">");
- } else {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">");
- }
- } else {
- if (k.enumeration != String()) {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\" enum=\"" + k.enumeration + "\">");
+ if (!c.constants.is_empty()) {
+ _write_string(f, 1, "<constants>");
+ for (int i = 0; i < c.constants.size(); i++) {
+ const DocData::ConstantDoc &k = c.constants[i];
+ if (k.is_value_valid) {
+ if (k.enumeration != String()) {
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\" enum=\"" + k.enumeration + "\">");
+ } else {
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"" + k.value + "\">");
+ }
} else {
- _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\">");
+ if (k.enumeration != String()) {
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\" enum=\"" + k.enumeration + "\">");
+ } else {
+ _write_string(f, 2, "<constant name=\"" + k.name + "\" value=\"platform-dependent\">");
+ }
}
+ _write_string(f, 3, k.description.strip_edges().xml_escape());
+ _write_string(f, 2, "</constant>");
}
- _write_string(f, 3, k.description.strip_edges().xml_escape());
- _write_string(f, 2, "</constant>");
- }
- _write_string(f, 1, "</constants>");
+ _write_string(f, 1, "</constants>");
+ }
- if (c.theme_properties.size()) {
+ if (!c.theme_properties.is_empty()) {
c.theme_properties.sort();
_write_string(f, 1, "<theme_items>");
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index d8f0367b33..9ff91179c1 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -5967,7 +5967,7 @@ EditorNode::EditorNode() {
EDITOR_DEF_RST("interface/editor/save_each_scene_on_quit", true);
EDITOR_DEF("interface/editor/show_update_spinner", false);
EDITOR_DEF("interface/editor/update_continuously", false);
- EDITOR_DEF_RST("interface/scene_tabs/restore_scenes_on_load", false);
+ EDITOR_DEF_RST("interface/scene_tabs/restore_scenes_on_load", true);
EDITOR_DEF_RST("interface/scene_tabs/show_thumbnail_on_hover", true);
EDITOR_DEF_RST("interface/inspector/capitalize_properties", true);
EDITOR_DEF_RST("interface/inspector/default_float_step", 0.001);
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index a4ab749db4..31c62880e2 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -135,6 +135,10 @@ void EditorResourcePicker::_file_selected(const String &p_path) {
_update_resource();
}
+void EditorResourcePicker::_file_quick_selected() {
+ _file_selected(quick_open->get_selected());
+}
+
void EditorResourcePicker::_update_menu() {
_update_menu_items();
@@ -153,7 +157,10 @@ void EditorResourcePicker::_update_menu_items() {
// Add options for creating specific subtypes of the base resource type.
set_create_options(edit_menu);
- // Add an option to load a resource from a file.
+ // Add an option to load a resource from a file using the QuickOpen dialog.
+ edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Quick Load"), OBJ_MENU_QUICKLOAD);
+
+ // Add an option to load a resource from a file using the regular file dialog.
edit_menu->add_icon_item(get_theme_icon(SNAME("Load"), SNAME("EditorIcons")), TTR("Load"), OBJ_MENU_LOAD);
// Add options for changing existing value of the resource.
@@ -246,6 +253,17 @@ void EditorResourcePicker::_edit_menu_cbk(int p_which) {
file_dialog->popup_file_dialog();
} break;
+ case OBJ_MENU_QUICKLOAD: {
+ if (!quick_open) {
+ quick_open = memnew(EditorQuickOpen);
+ add_child(quick_open);
+ quick_open->connect("quick_open", callable_mp(this, &EditorResourcePicker::_file_quick_selected));
+ }
+
+ quick_open->popup_dialog(base_type);
+ quick_open->set_title(TTR("Resource"));
+ } break;
+
case OBJ_MENU_EDIT: {
if (edited_resource.is_valid()) {
emit_signal(SNAME("resource_selected"), edited_resource);
diff --git a/editor/editor_resource_picker.h b/editor/editor_resource_picker.h
index d77c31f831..d0dad0287b 100644
--- a/editor/editor_resource_picker.h
+++ b/editor/editor_resource_picker.h
@@ -32,6 +32,7 @@
#define EDITOR_RESOURCE_PICKER_H
#include "editor_file_dialog.h"
+#include "quick_open.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/popup_menu.h"
@@ -54,9 +55,11 @@ class EditorResourcePicker : public HBoxContainer {
TextureRect *preview_rect;
Button *edit_button;
EditorFileDialog *file_dialog = nullptr;
+ EditorQuickOpen *quick_open = nullptr;
enum MenuOption {
OBJ_MENU_LOAD,
+ OBJ_MENU_QUICKLOAD,
OBJ_MENU_EDIT,
OBJ_MENU_CLEAR,
OBJ_MENU_MAKE_UNIQUE,
@@ -75,6 +78,7 @@ class EditorResourcePicker : public HBoxContainer {
void _update_resource_preview(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, ObjectID p_obj);
void _resource_selected();
+ void _file_quick_selected();
void _file_selected(const String &p_path);
void _update_menu();
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index 1953270b08..a255847a56 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -592,18 +592,16 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("editors/3d/navigation/warped_mouse_panning", true);
// 3D: Navigation feel
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_sensitivity", 0.4, "0.0,2,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_inertia", 0.05, "0.0,1,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/translation_inertia", 0.15, "0.0,1,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/zoom_inertia", 0.075, "0.0,1,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/manipulation_orbit_inertia", 0.075, "0.0,1,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/manipulation_translation_inertia", 0.075, "0.0,1,0.01")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_sensitivity", 0.25, "0.01,2,0.001")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/orbit_inertia", 0.0, "0,1,0.001")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/translation_inertia", 0.05, "0,1,0.001")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/navigation_feel/zoom_inertia", 0.05, "0,1,0.001")
// 3D: Freelook
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_navigation_scheme", 0, "Default,Partially Axis-Locked (id Tech),Fully Axis-Locked (Minecraft)")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_sensitivity", 0.4, "0.0,2,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_inertia", 0.1, "0.0,1,0.01")
- EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_base_speed", 5.0, "0.0,10,0.01")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_sensitivity", 0.25, "0.01,2,0.001")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_inertia", 0.0, "0,1,0.001")
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "editors/3d/freelook/freelook_base_speed", 5.0, "0,10,0.01")
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "editors/3d/freelook/freelook_activation_modifier", 0, "None,Shift,Alt,Meta,Ctrl")
_initial_set("editors/3d/freelook/freelook_speed_zoom_link", false);
diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h
index 414e0c1fe6..1bb5ef33ce 100644
--- a/editor/import/resource_importer_obj.h
+++ b/editor/import/resource_importer_obj.h
@@ -64,6 +64,9 @@ public:
virtual Error import(const String &p_source_file, const String &p_save_path, const Map<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files = nullptr, Variant *r_metadata = nullptr) override;
+ // Threaded import can currently cause deadlocks, see GH-48265.
+ virtual bool can_import_threaded() const override { return false; }
+
ResourceImporterOBJ();
};
diff --git a/editor/import/resource_importer_texture_atlas.cpp b/editor/import/resource_importer_texture_atlas.cpp
index dec1466da1..869af209d3 100644
--- a/editor/import/resource_importer_texture_atlas.cpp
+++ b/editor/import/resource_importer_texture_atlas.cpp
@@ -131,9 +131,9 @@ static void _plot_triangle(Vector2i *vertices, const Vector2i &p_offset, bool p_
double xf = x[0];
double xt = x[0] + dx_upper; // if y[0] == y[1], special case
int max_y = MIN(y[2], height - p_offset.y - 1);
- for (int yi = y[0]; yi <= max_y; yi++) {
+ for (int yi = y[0]; yi < max_y; yi++) {
if (yi >= 0) {
- for (int xi = (xf > 0 ? int(xf) : 0); xi <= (xt < width ? xt : width - 1); xi++) {
+ for (int xi = (xf > 0 ? int(xf) : 0); xi < (xt < width ? xt : width - 1); xi++) {
int px = xi, py = yi;
int sx = px, sy = py;
sx = CLAMP(sx, 0, src_width - 1);
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index 030d90eeca..24cb660f7a 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -66,9 +66,13 @@ void AnimationNodeBlendTreeEditor::remove_custom_type(const Ref<Script> &p_scrip
_update_options_menu();
}
-void AnimationNodeBlendTreeEditor::_update_options_menu() {
+void AnimationNodeBlendTreeEditor::_update_options_menu(bool p_has_input_ports) {
add_node->get_popup()->clear();
+ add_node->get_popup()->set_size(Size2i(-1, -1));
for (int i = 0; i < add_options.size(); i++) {
+ if (p_has_input_ports && add_options[i].input_port_count == 0) {
+ continue;
+ }
add_node->get_popup()->add_item(add_options[i].name, i);
}
@@ -309,6 +313,11 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
return;
}
+ if (!from_node.is_empty() && anode->get_input_count() == 0) {
+ from_node = "";
+ return;
+ }
+
Point2 instance_pos = graph->get_scroll_ofs();
if (use_popup_menu_position) {
instance_pos += popup_menu_position;
@@ -328,11 +337,51 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
undo_redo->create_action(TTR("Add Node to BlendTree"));
undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name);
+
+ if (!from_node.is_empty()) {
+ undo_redo->add_do_method(blend_tree.ptr(), "connect_node", name, 0, from_node);
+ from_node = "";
+ }
+ if (!to_node.is_empty() && to_slot != -1) {
+ undo_redo->add_do_method(blend_tree.ptr(), "connect_node", to_node, to_slot, name);
+ to_node = "";
+ to_slot = -1;
+ }
+
undo_redo->add_do_method(this, "_update_graph");
undo_redo->add_undo_method(this, "_update_graph");
undo_redo->commit_action();
}
+void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position) {
+ _update_options_menu(p_has_input_ports);
+ use_popup_menu_position = true;
+ popup_menu_position = p_popup_position;
+ add_node->get_popup()->set_position(p_node_position);
+ add_node->get_popup()->popup();
+}
+
+void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
+ _popup(false, graph->get_local_mouse_position(), p_position);
+}
+
+void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) {
+ Ref<AnimationNode> node = blend_tree->get_node(p_from);
+ if (node.is_valid()) {
+ from_node = p_from;
+ _popup(true, p_release_position, graph->get_global_mouse_position());
+ }
+}
+
+void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position) {
+ Ref<AnimationNode> node = blend_tree->get_node(p_to);
+ if (node.is_valid()) {
+ to_node = p_to;
+ to_slot = p_to_slot;
+ _popup(false, p_release_position, graph->get_global_mouse_position());
+ }
+}
+
void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) {
updating = true;
undo_redo->create_action(TTR("Node Moved"));
@@ -431,14 +480,6 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request() {
undo_redo->commit_action();
}
-void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) {
- _update_options_menu();
- use_popup_menu_position = true;
- popup_menu_position = graph->get_local_mouse_position();
- add_node->get_popup()->set_position(p_position);
- add_node->get_popup()->popup();
-}
-
void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
ERR_FAIL_COND(!gn);
@@ -890,6 +931,8 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
graph->connect("scroll_offset_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_scroll_changed));
graph->connect("delete_nodes_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_delete_nodes_request));
graph->connect("popup_request", callable_mp(this, &AnimationNodeBlendTreeEditor::_popup_request));
+ graph->connect("connection_to_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_to_empty));
+ graph->connect("connection_from_empty", callable_mp(this, &AnimationNodeBlendTreeEditor::_connection_from_empty));
float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
@@ -905,13 +948,13 @@ AnimationNodeBlendTreeEditor::AnimationNodeBlendTreeEditor() {
add_node->connect("about_to_popup", callable_mp(this, &AnimationNodeBlendTreeEditor::_update_options_menu));
add_options.push_back(AddOption("Animation", "AnimationNodeAnimation"));
- add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot"));
- add_options.push_back(AddOption("Add2", "AnimationNodeAdd2"));
- add_options.push_back(AddOption("Add3", "AnimationNodeAdd3"));
- add_options.push_back(AddOption("Blend2", "AnimationNodeBlend2"));
- add_options.push_back(AddOption("Blend3", "AnimationNodeBlend3"));
- add_options.push_back(AddOption("Seek", "AnimationNodeTimeSeek"));
- add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale"));
+ add_options.push_back(AddOption("OneShot", "AnimationNodeOneShot", 2));
+ add_options.push_back(AddOption("Add2", "AnimationNodeAdd2", 2));
+ add_options.push_back(AddOption("Add3", "AnimationNodeAdd3", 3));
+ add_options.push_back(AddOption("Blend2", "AnimationNodeBlend2", 2));
+ add_options.push_back(AddOption("Blend3", "AnimationNodeBlend3", 3));
+ add_options.push_back(AddOption("Seek", "AnimationNodeTimeSeek", 1));
+ add_options.push_back(AddOption("TimeScale", "AnimationNodeTimeScale", 1));
add_options.push_back(AddOption("Transition", "AnimationNodeTransition"));
add_options.push_back(AddOption("BlendTree", "AnimationNodeBlendTree"));
add_options.push_back(AddOption("BlendSpace1D", "AnimationNodeBlendSpace1D"));
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h
index 9f09069719..0fcafad40e 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.h
+++ b/editor/plugins/animation_blend_tree_editor_plugin.h
@@ -64,22 +64,28 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
Map<StringName, ProgressBar *> animations;
Vector<EditorProperty *> visible_properties;
+ String to_node = "";
+ int to_slot = -1;
+ String from_node = "";
+
void _update_graph();
struct AddOption {
String name;
String type;
Ref<Script> script;
- AddOption(const String &p_name = String(), const String &p_type = String()) :
+ int input_port_count;
+ AddOption(const String &p_name = String(), const String &p_type = String(), bool p_input_port_count = 0) :
name(p_name),
- type(p_type) {
+ type(p_type),
+ input_port_count(p_input_port_count) {
}
};
Vector<AddOption> add_options;
void _add_node(int p_idx);
- void _update_options_menu();
+ void _update_options_menu(bool p_has_input_ports = false);
static AnimationNodeBlendTreeEditor *singleton;
@@ -98,7 +104,6 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _anim_selected(int p_index, Array p_options, const String &p_node);
void _delete_request(const String &p_which);
void _delete_nodes_request();
- void _popup_request(const Vector2 &p_position);
bool _update_filters(const Ref<AnimationNode> &anode);
void _edit_filters(const String &p_which);
@@ -106,6 +111,11 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin {
void _filter_toggled();
Ref<AnimationNode> _filter_edit;
+ void _popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position);
+ void _popup_request(const Vector2 &p_position);
+ void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position);
+ void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position);
+
void _property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing);
void _removed_from_graph();
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 5263352502..cae8df1193 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -265,15 +265,13 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
if (is_freelook_active()) {
// Higher inertia should increase "lag" (lerp with factor between 0 and 1)
// Inertia of zero should produce instant movement (lerp with factor of 1) in this case it returns a really high value and gets clamped to 1.
- real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
- inertia = MAX(0.001, inertia);
+ const real_t inertia = EDITOR_GET("editors/3d/freelook/freelook_inertia");
real_t factor = (1.0 / inertia) * p_interp_delta;
// We interpolate a different point here, because in freelook mode the focus point (cursor.pos) orbits around eye_pos
camera_cursor.eye_pos = old_camera_cursor.eye_pos.lerp(cursor.eye_pos, CLAMP(factor, 0, 1));
- real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- orbit_inertia = MAX(0.0001, orbit_inertia);
+ const real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
@@ -289,24 +287,9 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) {
camera_cursor.pos = camera_cursor.eye_pos + forward * camera_cursor.distance;
} else {
- //when not being manipulated, move softly
- real_t free_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
- real_t free_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
- //when being manipulated, move more quickly
- real_t manip_orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_orbit_inertia");
- real_t manip_translation_inertia = EDITOR_GET("editors/3d/navigation_feel/manipulation_translation_inertia");
-
- real_t zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
-
- //determine if being manipulated
- bool manipulated = Input::get_singleton()->get_mouse_button_mask() & (2 | 4);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_SHIFT);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_ALT);
- manipulated |= Input::get_singleton()->is_key_pressed(KEY_CTRL);
-
- real_t orbit_inertia = MAX(0.00001, manipulated ? manip_orbit_inertia : free_orbit_inertia);
- real_t translation_inertia = MAX(0.0001, manipulated ? manip_translation_inertia : free_translation_inertia);
- zoom_inertia = MAX(0.0001, zoom_inertia);
+ const real_t orbit_inertia = EDITOR_GET("editors/3d/navigation_feel/orbit_inertia");
+ const real_t translation_inertia = EDITOR_GET("editors/3d/navigation_feel/translation_inertia");
+ const real_t zoom_inertia = EDITOR_GET("editors/3d/navigation_feel/zoom_inertia");
camera_cursor.x_rot = Math::lerp(old_camera_cursor.x_rot, cursor.x_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
camera_cursor.y_rot = Math::lerp(old_camera_cursor.y_rot, cursor.y_rot, MIN(1.f, p_interp_delta * (1 / orbit_inertia)));
@@ -4196,7 +4179,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, Edito
VBoxContainer *vbox = memnew(VBoxContainer);
surface->add_child(vbox);
- vbox->set_position(Point2(10, 10) * EDSCALE);
+ vbox->set_offset(SIDE_LEFT, 10 * EDSCALE);
+ vbox->set_offset(SIDE_TOP, 10 * EDSCALE);
view_menu = memnew(MenuButton);
view_menu->set_flat(false);
@@ -4820,7 +4804,7 @@ void _update_all_gizmos(Node *p_node) {
}
void Node3DEditor::update_all_gizmos(Node *p_node) {
- if (!p_node && get_tree()) {
+ if (!p_node && is_inside_tree()) {
p_node = get_tree()->get_edited_scene_root();
}
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index ee9103be44..07e4d4ebf0 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -808,39 +808,35 @@ void ScriptEditor::_copy_script_path() {
}
void ScriptEditor::_close_other_tabs() {
- int child_count = tab_container->get_child_count();
int current_idx = tab_container->get_current_tab();
- for (int i = child_count - 1; i >= 0; i--) {
- if (i == current_idx) {
- continue;
- }
-
- tab_container->set_current_tab(i);
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
-
- if (se) {
- // Maybe there are unsaved changes
- if (se->is_unsaved()) {
- _ask_close_current_unsaved_tab(se);
- continue;
- }
+ for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+ if (i != current_idx) {
+ script_close_queue.push_back(i);
}
-
- _close_current_tab(false);
}
+ _queue_close_tabs();
}
void ScriptEditor::_close_all_tabs() {
- int child_count = tab_container->get_child_count();
- for (int i = child_count - 1; i >= 0; i--) {
- tab_container->set_current_tab(i);
- ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i));
+ for (int i = tab_container->get_child_count() - 1; i >= 0; i--) {
+ script_close_queue.push_back(i);
+ }
+ _queue_close_tabs();
+}
+
+void ScriptEditor::_queue_close_tabs() {
+ while (!script_close_queue.is_empty()) {
+ int idx = script_close_queue.front()->get();
+ script_close_queue.pop_front();
+ tab_container->set_current_tab(idx);
+ ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(idx));
if (se) {
- // Maybe there are unsaved changes
+ // Maybe there are unsaved changes.
if (se->is_unsaved()) {
_ask_close_current_unsaved_tab(se);
- continue;
+ erase_tab_confirm->connect(SceneStringNames::get_singleton()->visibility_changed, callable_mp(this, &ScriptEditor::_queue_close_tabs), varray(), CONNECT_ONESHOT);
+ break;
}
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index 920c3070e6..7620605570 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -309,6 +309,7 @@ class ScriptEditor : public PanelContainer {
int history_pos;
List<String> previous_scripts;
+ List<int> script_close_queue;
void _tab_changed(int p_which);
void _menu_option(int p_option);
@@ -341,6 +342,7 @@ class ScriptEditor : public PanelContainer {
void _close_docs_tab();
void _close_other_tabs();
void _close_all_tabs();
+ void _queue_close_tabs();
void _copy_script_path();