diff options
38 files changed, 746 insertions, 207 deletions
diff --git a/core/script_debugger_remote.cpp b/core/script_debugger_remote.cpp index 5655a4d5e4..5e06339b9e 100644 --- a/core/script_debugger_remote.cpp +++ b/core/script_debugger_remote.cpp @@ -35,6 +35,8 @@ #include "os/input.h" #include "os/os.h" #include "project_settings.h" +#include "scene/main/node.h" + void ScriptDebuggerRemote::_send_video_memory() { List<ResourceUsage> usage; @@ -201,20 +203,39 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) List<String> members; List<Variant> member_vals; - + if (ScriptInstance *inst = p_script->debug_get_stack_level_instance(lv)) { + members.push_back("self"); + member_vals.push_back(inst->get_owner()); + } p_script->debug_get_stack_level_members(lv, &members, &member_vals); - ERR_CONTINUE(members.size() != member_vals.size()); List<String> locals; List<Variant> local_vals; - p_script->debug_get_stack_level_locals(lv, &locals, &local_vals); - ERR_CONTINUE(locals.size() != local_vals.size()); + List<String> globals; + List<Variant> globals_vals; + p_script->debug_get_globals(&globals, &globals_vals); + ERR_CONTINUE(globals.size() != globals_vals.size()); + packet_peer_stream->put_var("stack_frame_vars"); - packet_peer_stream->put_var(2 + locals.size() * 2 + members.size() * 2); + packet_peer_stream->put_var(3 + (locals.size() + members.size() + globals.size()) * 2); + + { //locals + packet_peer_stream->put_var(locals.size()); + + List<String>::Element *E = locals.front(); + List<Variant>::Element *F = local_vals.front(); + + while (E) { + _put_variable(E->get(), F->get()); + + E = E->next(); + F = F->next(); + } + } { //members packet_peer_stream->put_var(members.size()); @@ -231,11 +252,11 @@ void ScriptDebuggerRemote::debug(ScriptLanguage *p_script, bool p_can_continue) } } - { //locals - packet_peer_stream->put_var(locals.size()); + { //globals + packet_peer_stream->put_var(globals.size()); - List<String>::Element *E = locals.front(); - List<Variant>::Element *F = local_vals.front(); + List<String>::Element *E = globals.front(); + List<Variant>::Element *F = globals_vals.front(); while (E) { _put_variable(E->get(), F->get()); @@ -532,56 +553,88 @@ void ScriptDebuggerRemote::_send_object_id(ObjectID p_id) { if (!obj) return; - List<PropertyInfo> pinfo; - obj->get_property_list(&pinfo, true); + typedef Pair<PropertyInfo, Variant> PropertyDesc; + List<PropertyDesc> properties; - int props_to_send = 0; - for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { + if (ScriptInstance *si = obj->get_script_instance()) { + if (!si->get_script().is_null()) { - if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { - props_to_send++; - } - } + Set<StringName> members; + si->get_script()->get_members(&members); + for (Set<StringName>::Element *E = members.front(); E; E = E->next()) { - packet_peer_stream->put_var("message:inspect_object"); - packet_peer_stream->put_var(props_to_send * 5 + 4); - packet_peer_stream->put_var(p_id); - packet_peer_stream->put_var(obj->get_class()); - if (obj->is_class("Resource") || obj->is_class("Node")) - packet_peer_stream->put_var(obj->call("get_path")); - else - packet_peer_stream->put_var(""); + Variant m; + if (si->get(E->get(), m)) { + PropertyInfo pi(m.get_type(), String("Members/") + E->get()); + properties.push_back(PropertyDesc(pi, m)); + } + } - packet_peer_stream->put_var(props_to_send); + Map<StringName, Variant> constants; + si->get_script()->get_constants(&constants); + for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { + PropertyInfo pi(E->value().get_type(), (String("Constants/") + E->key())); + properties.push_back(PropertyDesc(pi, E->value())); + } + } + } + if (Node *node = Object::cast_to<Node>(obj)) { + PropertyInfo pi(Variant::NODE_PATH, String("Node/path")); + properties.push_front(PropertyDesc(pi, node->get_path())); + } else if (Resource *res = Object::cast_to<Resource>(obj)) { + if (Script *s = Object::cast_to<Script>(res)) { + Map<StringName, Variant> constants; + s->get_constants(&constants); + for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { + PropertyInfo pi(E->value().get_type(), String("Constants/") + E->key()); + properties.push_front(PropertyDesc(pi, E->value())); + } + } + } + List<PropertyInfo> pinfo; + obj->get_property_list(&pinfo, true); for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) { - if (E->get().usage & (PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_CATEGORY)) { + properties.push_back(PropertyDesc(E->get(), obj->get(E->get().name))); + } + } - if (E->get().usage & PROPERTY_USAGE_CATEGORY) { - packet_peer_stream->put_var("*" + E->get().name); - } else { - packet_peer_stream->put_var(E->get().name); - } - - Variant var = obj->get(E->get().name); - packet_peer_stream->put_var(E->get().type); - //only send information that can be sent.. - - int len = 0; //test how big is this to encode - encode_variant(var, NULL, len); - - if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size - packet_peer_stream->put_var(PROPERTY_HINT_OBJECT_TOO_BIG); - packet_peer_stream->put_var(""); - packet_peer_stream->put_var(Variant()); - } else { - packet_peer_stream->put_var(E->get().hint); - packet_peer_stream->put_var(E->get().hint_string); - packet_peer_stream->put_var(var); - } + Array send_props; + for (int i = 0; i < properties.size(); i++) { + const PropertyInfo &pi = properties[i].first; + const Variant &var = properties[i].second; + RES res = var; + + Array prop; + prop.push_back(pi.name); + prop.push_back(pi.type); + + //only send information that can be sent.. + int len = 0; //test how big is this to encode + encode_variant(var, NULL, len); + if (len > packet_peer_stream->get_output_buffer_max_size()) { //limit to max size + prop.push_back(PROPERTY_HINT_OBJECT_TOO_BIG); + prop.push_back(""); + prop.push_back(pi.usage); + prop.push_back(Variant()); + } else { + prop.push_back(pi.hint); + if (res.is_null()) + prop.push_back(pi.hint_string); + else + prop.push_back(String("RES:") + res->get_path()); + prop.push_back(pi.usage); + prop.push_back(var); } + send_props.push_back(prop); } + + packet_peer_stream->put_var("message:inspect_object"); + packet_peer_stream->put_var(3); + packet_peer_stream->put_var(p_id); + packet_peer_stream->put_var(obj->get_class()); + packet_peer_stream->put_var(send_props); } void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value) { @@ -590,7 +643,11 @@ void ScriptDebuggerRemote::_set_object_property(ObjectID p_id, const String &p_p if (!obj) return; - obj->set(p_property, p_value); + String prop_name = p_property; + if (p_property.begins_with("Members/")) + prop_name = p_property.substr(8, p_property.length()); + + obj->set(prop_name, p_value); } void ScriptDebuggerRemote::_poll_events() { diff --git a/core/script_language.h b/core/script_language.h index 5da72d0492..3d01381f3b 100644 --- a/core/script_language.h +++ b/core/script_language.h @@ -120,6 +120,9 @@ public: virtual int get_member_line(const StringName &p_member) const { return -1; } + virtual void get_constants(Map<StringName, Variant> *p_constants) {} + virtual void get_members(Set<StringName> *p_constants) {} + Script() {} }; @@ -130,6 +133,7 @@ public: virtual void get_property_list(List<PropertyInfo> *p_properties) const = 0; virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = NULL) const = 0; + virtual Object *get_owner() { return NULL; } virtual void get_property_state(List<Pair<StringName, Variant> > &state); virtual void get_method_list(List<MethodInfo> *p_list) const = 0; @@ -244,7 +248,8 @@ public: virtual String debug_get_stack_level_source(int p_level) const = 0; virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; + virtual ScriptInstance *debug_get_stack_level_instance(int p_level) { return NULL; } + virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) = 0; virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) = 0; struct StackInfo { diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp new file mode 100644 index 0000000000..5b5a7ec9b0 --- /dev/null +++ b/editor/dictionary_property_edit.cpp @@ -0,0 +1,189 @@ +/*************************************************************************/ +/* dictionary_property_edit.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 "dictionary_property_edit.h" +#include "editor_node.h" + +void DictionaryPropertyEdit::_notif_change() { + _change_notify(); +} + +void DictionaryPropertyEdit::_notif_changev(const String &p_v) { + _change_notify(p_v.utf8().get_data()); +} + +void DictionaryPropertyEdit::_set_key(const Variant &p_old_key, const Variant &p_new_key) { + + // TODO: Set key of a dictionary is not allowd yet + return; +} + +void DictionaryPropertyEdit::_set_value(const Variant &p_key, const Variant &p_value) { + + Dictionary dict = get_dictionary(); + dict[p_key] = p_value; + Object *o = ObjectDB::get_instance(obj); + if (!o) + return; + + o->set(property, dict); +} + +Variant DictionaryPropertyEdit::get_dictionary() const { + + Object *o = ObjectDB::get_instance(obj); + if (!o) + return Dictionary(); + Variant dict = o->get(property); + if (dict.get_type() != Variant::DICTIONARY) + return Dictionary(); + return dict; +} + +void DictionaryPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const { + + Dictionary dict = get_dictionary(); + + Array keys = dict.keys(); + keys.sort(); + + for (int i = 0; i < keys.size(); i++) { + String index = itos(i); + + const Variant &key = keys[i]; + PropertyInfo pi(key.get_type(), index + ": key"); + p_list->push_back(pi); + + const Variant &value = dict[key]; + pi = PropertyInfo(value.get_type(), index + ": value"); + p_list->push_back(pi); + } +} + +void DictionaryPropertyEdit::edit(Object *p_obj, const StringName &p_prop) { + + property = p_prop; + obj = p_obj->get_instance_id(); +} + +Node *DictionaryPropertyEdit::get_node() { + + Object *o = ObjectDB::get_instance(obj); + if (!o) + return NULL; + + return cast_to<Node>(o); +} + +void DictionaryPropertyEdit::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_set_key"), &DictionaryPropertyEdit::_set_key); + ClassDB::bind_method(D_METHOD("_set_value"), &DictionaryPropertyEdit::_set_value); + ClassDB::bind_method(D_METHOD("_notif_change"), &DictionaryPropertyEdit::_notif_change); + ClassDB::bind_method(D_METHOD("_notif_changev"), &DictionaryPropertyEdit::_notif_changev); +} + +bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_value) { + + Dictionary dict = get_dictionary(); + Array keys = dict.keys(); + keys.sort(); + + String pn = p_name; + int slash = pn.find(": "); + if (slash != -1 && pn.length() > slash) { + String type = pn.substr(slash + 2, pn.length()); + int index = pn.substr(0, slash).to_int(); + if (type == "key" && index < keys.size()) { + + const Variant &key = keys[index]; + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Change Dictionary Key")); + ur->add_do_method(this, "_set_key", key, p_value); + ur->add_undo_method(this, "_set_key", p_value, key); + ur->add_do_method(this, "_notif_changev", p_name); + ur->add_undo_method(this, "_notif_changev", p_name); + ur->commit_action(); + + return true; + } else if (type == "value" && index < keys.size()) { + const Variant &key = keys[index]; + if (dict.has(key)) { + + Variant value = dict[key]; + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + + ur->create_action(TTR("Change Dictionary Value")); + ur->add_do_method(this, "_set_value", key, p_value); + ur->add_undo_method(this, "_set_value", key, value); + ur->add_do_method(this, "_notif_changev", p_name); + ur->add_undo_method(this, "_notif_changev", p_name); + ur->commit_action(); + + return true; + } + } + } + + return false; +} + +bool DictionaryPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const { + + Dictionary dict = get_dictionary(); + Array keys = dict.keys(); + keys.sort(); + + String pn = p_name; + int slash = pn.find(": "); + + if (slash != -1 && pn.length() > slash) { + + String type = pn.substr(slash + 2, pn.length()); + int index = pn.substr(0, slash).to_int(); + + if (type == "key" && index < keys.size()) { + r_ret = keys[index]; + return true; + } else if (type == "value" && index < keys.size()) { + const Variant &key = keys[index]; + if (dict.has(key)) { + r_ret = dict[key]; + return true; + } + } + } + + return false; +} + +DictionaryPropertyEdit::DictionaryPropertyEdit() { + obj = 0; +} diff --git a/editor/dictionary_property_edit.h b/editor/dictionary_property_edit.h new file mode 100644 index 0000000000..7a86727fb2 --- /dev/null +++ b/editor/dictionary_property_edit.h @@ -0,0 +1,62 @@ +/*************************************************************************/ +/* dictionary_property_edit.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* http://www.godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 DICTIONARY_PROPERTY_EDIT_H +#define DICTIONARY_PROPERTY_EDIT_H + +#include "scene/main/node.h" + +class DictionaryPropertyEdit : public Reference { + GDCLASS(DictionaryPropertyEdit, Reference); + + ObjectID obj; + StringName property; + + void _notif_change(); + void _notif_changev(const String &p_v); + void _set_key(const Variant &p_old_key, const Variant &p_new_key); + void _set_value(const Variant &p_key, const Variant &p_value); + + Variant get_dictionary() const; + +protected: + static void _bind_methods(); + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + void _get_property_list(List<PropertyInfo> *p_list) const; + +public: + void edit(Object *p_obj, const StringName &p_prop); + + Node *get_node(); + + DictionaryPropertyEdit(); +}; + +#endif // DICTIONARY_PROPERTY_EDIT_H diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index c0e2e46f14..109f132d76 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -303,8 +303,7 @@ void EditorNode::_notification(int p_what) { if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { scene_tabs->set_tab_close_display_policy((bool(EDITOR_DEF("interface/editor/always_show_close_button_in_scene_tabs", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY)); - property_editor->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); - Ref<Theme> theme = create_custom_theme(theme_base->get_theme()); + Ref<Theme> theme = create_editor_theme(theme_base->get_theme()); theme_base->set_theme(theme); gui_base->set_theme(theme); @@ -1368,6 +1367,8 @@ void EditorNode::_prepare_history() { } } else if (Object::cast_to<Node>(obj)) { text = Object::cast_to<Node>(obj)->get_name(); + } else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) { + text = obj->call("get_title"); } else { text = obj->get_class(); } @@ -1463,6 +1464,7 @@ void EditorNode::_edit_current() { object_menu->set_disabled(true); + bool capitalize = bool(EDITOR_DEF("interface/editor/capitalize_properties", true)); bool is_resource = current_obj->is_class("Resource"); bool is_node = current_obj->is_class("Node"); resource_save_button->set_disabled(!is_resource); @@ -1516,6 +1518,11 @@ void EditorNode::_edit_current() { } else { + if (current_obj->is_class("ScriptEditorDebuggerInspectedObject")) { + editable_warning = TTR("This is a remote object so changes to it will not be kept.\nPlease read the documentation relevant to debugging to better understand this workflow."); + capitalize = false; + } + property_editor->edit(current_obj); node_dock->set_node(NULL); } @@ -1525,6 +1532,10 @@ void EditorNode::_edit_current() { property_editable_warning_dialog->set_text(editable_warning); } + if (property_editor->is_capitalize_paths_enabled() != capitalize) { + property_editor->set_enable_capitalize_paths(capitalize); + } + /* Take care of PLUGIN EDITOR */ EditorPlugin *main_plugin = editor_data.get_editor(current_obj); diff --git a/editor/editor_path.cpp b/editor/editor_path.cpp index 0587939a1a..f0d3c29c11 100644 --- a/editor/editor_path.cpp +++ b/editor/editor_path.cpp @@ -149,14 +149,14 @@ void EditorPath::_notification(int p_what) { if (name == "") name = r->get_class(); - } else if (Object::cast_to<Node>(obj)) { - + } else if (obj->is_class("ScriptEditorDebuggerInspectedObject")) + name = obj->call("get_title"); + else if (Object::cast_to<Node>(obj)) name = Object::cast_to<Node>(obj)->get_name(); - } else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") { + else if (Object::cast_to<Resource>(obj) && Object::cast_to<Resource>(obj)->get_name() != "") name = Object::cast_to<Resource>(obj)->get_name(); - } else { + else name = obj->get_class(); - } set_tooltip(obj->get_class()); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index d228dd2581..9817ce0047 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -135,7 +135,7 @@ bool EditorSettings::_get(const StringName &p_name, Variant &r_ret) const { void EditorSettings::_initial_set(const StringName &p_name, const Variant &p_value) { set(p_name, p_value); props[p_name].initial = p_value; - props[p_name].initial_set = true; + props[p_name].has_default_value = true; } struct _EVCSort { @@ -221,7 +221,7 @@ bool EditorSettings::has_default_value(const String &p_setting) const { if (!props.has(p_setting)) return false; - return props[p_setting].initial_set; + return props[p_setting].has_default_value; } void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { @@ -424,6 +424,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/2d/bone_ik_color", Color(0.9, 0.9, 0.45, 0.9)); _initial_set("editors/2d/keep_margins_when_changing_anchors", false); _initial_set("editors/2d/warped_mouse_panning", true); + _initial_set("editors/2d/simple_spacebar_panning", false); _initial_set("editors/2d/scroll_to_pan", false); _initial_set("editors/2d/pan_speed", 20); @@ -967,7 +968,7 @@ void EditorSettings::set_initial_value(const StringName &p_setting, const Varian if (!props.has(p_setting)) return; props[p_setting].initial = p_value; - props[p_setting].initial_set = true; + props[p_setting].has_default_value = true; } Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default) { @@ -975,10 +976,10 @@ Variant _EDITOR_DEF(const String &p_setting, const Variant &p_default) { Variant ret = p_default; if (EditorSettings::get_singleton()->has_setting(p_setting)) ret = EditorSettings::get_singleton()->get(p_setting); - if (!EditorSettings::get_singleton()->has_default_value(p_setting)) { - EditorSettings::get_singleton()->set_initial_value(p_setting, p_default); + else EditorSettings::get_singleton()->set(p_setting, p_default); - } + if (!EditorSettings::get_singleton()->has_default_value(p_setting)) + EditorSettings::get_singleton()->set_initial_value(p_setting, p_default); return ret; } diff --git a/editor/editor_settings.h b/editor/editor_settings.h index f11f4dfd43..a8c991a6d9 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -66,13 +66,13 @@ private: int order; Variant variant; Variant initial; - bool initial_set; + bool has_default_value; bool hide_from_editor; bool save; VariantContainer() { order = 0; hide_from_editor = false; - initial_set = false; + has_default_value = false; save = false; } VariantContainer(const Variant &p_variant, int p_order) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0f9f50095d..ae29b7420e 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -738,6 +738,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_stylebox("button", "Tabs", style_menu); theme->set_icon("increment", "TabContainer", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); theme->set_icon("decrement", "TabContainer", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_icon("increment", "Tabs", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); + theme->set_icon("decrement", "Tabs", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_icon("increment_highlight", "Tabs", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); + theme->set_icon("decrement_highlight", "Tabs", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_icon("increment_highlight", "TabContainer", theme->get_icon("GuiScrollArrowRight", "EditorIcons")); + theme->set_icon("decrement_highlight", "TabContainer", theme->get_icon("GuiScrollArrowLeft", "EditorIcons")); + theme->set_constant("hseparation", "Tabs", 4 * EDSCALE); // Content of each tab Ref<StyleBoxFlat> style_content_panel = style_default->duplicate(); diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index eea8177687..9c432323f4 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1447,6 +1447,15 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) { file_options->popup(); } +void FileSystemDock::_rmb_pressed(const Vector2 &p_pos) { + folder_options->clear(); + folder_options->set_size(Size2(1, 1)); + + folder_options->add_item(TTR("New Folder.."), FOLDER_NEW_FOLDER); + folder_options->set_position(files->get_global_position() + p_pos); + folder_options->popup(); +} + void FileSystemDock::select_file(const String &p_file) { navigate_to_path(p_file); @@ -1547,6 +1556,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_file_selected"), &FileSystemDock::_file_selected); ClassDB::bind_method(D_METHOD("_file_multi_selected"), &FileSystemDock::_file_multi_selected); ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock); + ClassDB::bind_method(D_METHOD("_rmb_pressed"), &FileSystemDock::_rmb_pressed); ADD_SIGNAL(MethodInfo("instance", PropertyInfo(Variant::POOL_STRING_ARRAY, "files"))); ADD_SIGNAL(MethodInfo("open")); @@ -1665,6 +1675,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { files->connect("item_rmb_selected", this, "_files_list_rmb_select"); files->connect("item_selected", this, "_file_selected"); files->connect("multi_selected", this, "_file_multi_selected"); + files->connect("rmb_clicked", this, "_rmb_pressed"); files->set_allow_rmb_select(true); file_list_vb->add_child(files); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index d100de8b72..f1fd342052 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -192,6 +192,7 @@ private: void _dir_rmb_pressed(const Vector2 &p_pos); void _files_list_rmb_select(int p_item, const Vector2 &p_pos); + void _rmb_pressed(const Vector2 &p_pos); struct FileInfo { String name; diff --git a/editor/icons/icon_GUI_ellipsis.svg b/editor/icons/icon_GUI_ellipsis.svg new file mode 100644 index 0000000000..5565fd2947 --- /dev/null +++ b/editor/icons/icon_GUI_ellipsis.svg @@ -0,0 +1,5 @@ +<svg width="14" height="8" version="1.1" viewBox="0 0 14 8" xmlns="http://www.w3.org/2000/svg"> +<g transform="translate(0 -1044.4)"> +<path transform="translate(0 1040.4)" d="m3.8594 4c-2.1381 0-3.8594 1.7213-3.8594 3.8594v0.28125c0 2.1381 1.7213 3.8594 3.8594 3.8594h6.2812c2.1381 0 3.8594-1.7213 3.8594-3.8594v-0.28125c0-2.1381-1.7213-3.8594-3.8594-3.8594zm-0.85938 3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#fff" fill-opacity=".39216"/> +</g> +</svg> diff --git a/editor/icons/icon_animation.svg b/editor/icons/icon_animation.svg index 146403ece5..600faeeddb 100644 --- a/editor/icons/icon_animation.svg +++ b/editor/icons/icon_animation.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 4 -1.5352v1.5352h0.001953a2 2 0 0 0 0.26562 1 2 2 0 0 0 1.7324 1h1v-1-1h-0.5a0.5 0.49999 0 0 1 -0.5 -0.5v-0.5-5a6 6 0 0 0 -6 -6zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm3.4414 2a1 1 0 0 1 0.88867 0.5 1 1 0 0 1 -0.36523 1.3652 1 1 0 0 1 -1.3672 -0.36523 1 1 0 0 1 0.36719 -1.3652 1 1 0 0 1 0.47656 -0.13477zm-6.9531 0.0019531a1 1 0 0 1 0.54688 0.13281 1 1 0 0 1 0.36719 1.3652 1 1 0 0 1 -1.3672 0.36523 1 1 0 0 1 -0.36523 -1.3652 1 1 0 0 1 0.81836 -0.49805zm0.023438 3.998a1 1 0 0 1 0.89062 0.5 1 1 0 0 1 -0.36719 1.3652 1 1 0 0 1 -1.3652 -0.36523 1 1 0 0 1 0.36523 -1.3652 1 1 0 0 1 0.47656 -0.13477zm6.9043 0.0019531a1 1 0 0 1 0.54883 0.13281 1 1 0 0 1 0.36523 1.3652 1 1 0 0 1 -1.3652 0.36523 1 1 0 0 1 -0.36719 -1.3652 1 1 0 0 1 0.81836 -0.49805zm-3.416 1.998a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#e0e0e0"/> -</g> +<path d="m8 2a6 6 0 0 0 -6 6 6 6 0 0 0 6 6 6 6 0 0 0 4 -1.5352v1.5352h0.001953a2 2 0 0 0 0.26562 1 2 2 0 0 0 1.7324 1h1v-1-1h-0.5a0.5 0.49999 0 0 1 -0.5 -0.5v-0.5-5a6 6 0 0 0 -6 -6zm0 1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1zm3.4414 2a1 1 0 0 1 0.88867 0.5 1 1 0 0 1 -0.36523 1.3652 1 1 0 0 1 -1.3672 -0.36523 1 1 0 0 1 0.36719 -1.3652 1 1 0 0 1 0.47656 -0.13477zm-6.9531 0.0019531a1 1 0 0 1 0.54688 0.13281 1 1 0 0 1 0.36719 1.3652 1 1 0 0 1 -1.3672 0.36523 1 1 0 0 1 -0.36523 -1.3652 1 1 0 0 1 0.81836 -0.49805zm0.023438 3.998a1 1 0 0 1 0.89062 0.5 1 1 0 0 1 -0.36719 1.3652 1 1 0 0 1 -1.3652 -0.36523 1 1 0 0 1 0.36523 -1.3652 1 1 0 0 1 0.47656 -0.13477zm6.9043 0.0019531a1 1 0 0 1 0.54883 0.13281 1 1 0 0 1 0.36523 1.3652 1 1 0 0 1 -1.3652 0.36523 1 1 0 0 1 -0.36719 -1.3652 1 1 0 0 1 0.81836 -0.49805zm-3.416 1.998a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1 -1 1 1 0 0 1 1 -1z" fill="#e0e0e0"/> </svg> diff --git a/editor/icons/icon_area.svg b/editor/icons/icon_area.svg index ac673d10fc..5e1a385f58 100644 --- a/editor/icons/icon_area.svg +++ b/editor/icons/icon_area.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#fc9c9c"/> -</g> +<path d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#fc9c9c"/> </svg> diff --git a/editor/icons/icon_area_2d.svg b/editor/icons/icon_area_2d.svg index d6ecb6abe5..28fc4d7804 100644 --- a/editor/icons/icon_area_2d.svg +++ b/editor/icons/icon_area_2d.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#a5b7f3"/> -</g> +<path d="m1 1v2 2h2v-2h2v-2h-4zm10 0v2h2v2h2v-4h-4zm-7 3v2 4 2h8v-2-6h-8zm2 2h4v4h-4v-4zm-5 5v2 2h2 2v-2h-2v-2h-2zm12 0v2h-2v2h4v-2-2h-2z" fill="#a5b7f3"/> </svg> diff --git a/editor/icons/icon_array_mesh.svg b/editor/icons/icon_array_mesh.svg index 68890c4366..867fc95b0c 100644 --- a/editor/icons/icon_array_mesh.svg +++ b/editor/icons/icon_array_mesh.svg @@ -1,5 +1,3 @@ <svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm10 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2zm-8 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#ffd684" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> -</g> +<path d="m3 1a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm10 0a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2zm-2 7v3h-3v2h3v3h2v-3h3v-2h-3v-3h-2zm-8 3a2 2 0 0 0 -2 2 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -2 -2z" color="#000000" color-rendering="auto" dominant-baseline="auto" fill="#ffd684" image-rendering="auto" shape-rendering="auto" solid-color="#000000" style="font-feature-settings:normal;font-variant-alternates:normal;font-variant-caps:normal;font-variant-east-asian:normal;font-variant-ligatures:normal;font-variant-numeric:normal;font-variant-position:normal;isolation:auto;mix-blend-mode:normal;shape-padding:0;text-decoration-color:#000000;text-decoration-line:none;text-decoration-style:solid;text-indent:0;text-orientation:mixed;text-transform:none;white-space:normal"/> </svg> diff --git a/editor/icons/icon_editor_handle_add.svg b/editor/icons/icon_editor_handle_add.svg deleted file mode 100644 index 0e7fe7129a..0000000000 --- a/editor/icons/icon_editor_handle_add.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> - <g transform="translate(0 -1044.4)"> - <ellipse cx="4" cy="1048.4" rx="4" ry="4" fill="#fff"/> - <ellipse cx="4" cy="1048.4" rx="2.8572" ry="2.8571" fill="#84ff84"/> - </g> -</svg> diff --git a/editor/icons/icon_editor_handle_selected.svg b/editor/icons/icon_editor_handle_selected.svg deleted file mode 100644 index 8d338c1fbd..0000000000 --- a/editor/icons/icon_editor_handle_selected.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="8" height="8" version="1.1" viewBox="0 0 8 8" xmlns="http://www.w3.org/2000/svg"> - <g transform="translate(0 -1044.4)"> - <ellipse cx="4" cy="1048.4" rx="4" ry="4" fill="#fff"/> - <ellipse cx="4" cy="1048.4" rx="2.8572" ry="2.8571" fill="#8484ff"/> - </g> -</svg> diff --git a/editor/icons/icon_h_button_array.svg b/editor/icons/icon_h_button_array.svg deleted file mode 100644 index 3f95dbbde1..0000000000 --- a/editor/icons/icon_h_button_array.svg +++ /dev/null @@ -1,5 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)"> -<path transform="translate(0 1036.4)" d="m4 1v3.1328l-1.4453-0.96484-1.1094 1.6641 3 2c0.3359 0.2239 0.77347 0.2239 1.1094 0l3-2-1.1094-1.6641-1.4453 0.96484v-3.1328h-2zm8 4v2h-2v2h2v2h2v-2h2v-2h-2v-2h-2zm-8.5 4c-0.831 0-1.5 0.669-1.5 1.5v0.5 1h-1v2h8v-2h-1v-1-0.5c0-0.831-0.669-1.5-1.5-1.5h-3z" fill="#a5efac"/> -</g> -</svg> diff --git a/editor/icons/icon_onion.svg b/editor/icons/icon_onion.svg new file mode 100644 index 0000000000..5bb2a99423 --- /dev/null +++ b/editor/icons/icon_onion.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<path d="m8 1c-2 2-7 4-7 8s3 6 7 6c-7-3-6.5995-7.703 0-13-2.2981 3.9516-5.4951 8.9197 0 13 4.8692-4.2391 2.7733-8.1815 1-12 5.5855 4.704 5.3995 8.6488-1 12 4 0 7-2 7-6s-5-6-7-8z" fill="#e0e0e0"/> +</svg> diff --git a/editor/icons/icon_v_button_array.svg b/editor/icons/icon_v_button_array.svg deleted file mode 100644 index ac7ce6064c..0000000000 --- a/editor/icons/icon_v_button_array.svg +++ /dev/null @@ -1,6 +0,0 @@ -<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> -<g transform="translate(0 -1036.4)" fill="#a5efac"> -<path transform="translate(0 1036.4)" d="m7 1v2.1328l-1.4453-0.96484-1.1094 1.6641 3 2c0.3359 0.2239 0.77347 0.2239 1.1094 0l3-2-1.1094-1.6641-1.4453 0.96484v-2.1328h-2zm-0.5 6c-0.831 0-1.5 0.669-1.5 1.5v0.5h-1v2h2v-2h4v2h2v-2h-1v-0.5c0-0.831-0.669-1.5-1.5-1.5h-3z"/> -<path d="m7 1046.4v2h-2v2h2v2h2v-2h2v-2h-2v-2z"/> -</g> -</svg> diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index b6ba09fb58..6cb4171f5a 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1858,7 +1858,17 @@ void CanvasItemEditor::_gui_input_viewport(const Ref<InputEvent> &p_event) { } if (drag == DRAG_NONE) { - if (((m->get_button_mask() & BUTTON_MASK_LEFT) && tool == TOOL_PAN) || (m->get_button_mask() & BUTTON_MASK_MIDDLE) || ((m->get_button_mask() & BUTTON_MASK_LEFT) && Input::get_singleton()->is_key_pressed(KEY_SPACE))) { + bool space_pressed = Input::get_singleton()->is_key_pressed(KEY_SPACE); + bool simple_panning = EditorSettings::get_singleton()->get("editors/2d/simple_spacebar_panning"); + int button = m->get_button_mask(); + + // Check if any of the panning triggers are activated + bool panning_tool = (button & BUTTON_MASK_LEFT) && tool == TOOL_PAN; + bool panning_middle_button = button & BUTTON_MASK_MIDDLE; + bool panning_spacebar = (button & BUTTON_MASK_LEFT) && space_pressed; + bool panning_spacebar_simple = space_pressed && simple_panning; + + if (panning_tool || panning_middle_button || panning_spacebar || panning_spacebar_simple) { // Pan the viewport Point2i relative; if (bool(EditorSettings::get_singleton()->get("editors/2d/warped_mouse_panning"))) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 32ec9b2ba9..3c2d52c128 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -2897,7 +2897,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) { EDITOR_DEF("text_editor/open_scripts/script_temperature_enabled", true); EDITOR_DEF("text_editor/open_scripts/highlight_current_script", true); EDITOR_DEF("text_editor/open_scripts/script_temperature_history_size", 15); - EDITOR_DEF("text_editor/open_scripts/current_script_background_color", Color(1, 1, 1, 0.5)); + EDITOR_DEF("text_editor/open_scripts/current_script_background_color", Color(1, 1, 1, 0.3)); EDITOR_DEF("text_editor/open_scripts/group_help_pages", true); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "text_editor/open_scripts/sort_scripts_by", PROPERTY_HINT_ENUM, "Name,Path")); EDITOR_DEF("text_editor/open_scripts/sort_scripts_by", 0); diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index 9733f49f42..bc7d8f4b14 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -40,6 +40,7 @@ #include "core/project_settings.h" #include "editor/array_property_edit.h" #include "editor/create_dialog.h" +#include "editor/dictionary_property_edit.h" #include "editor/editor_export.h" #include "editor/editor_file_system.h" #include "editor/editor_help.h" @@ -1157,7 +1158,8 @@ void CustomPropertyEditor::_node_path_selected(NodePath p_path) { node = Object::cast_to<Node>(owner); else if (owner->is_class("ArrayPropertyEdit")) node = Object::cast_to<ArrayPropertyEdit>(owner)->get_node(); - + else if (owner->is_class("DictionaryPropertyEdit")) + node = Object::cast_to<DictionaryPropertyEdit>(owner)->get_node(); if (!node) { v = p_path; emit_signal("variant_changed"); @@ -3215,9 +3217,14 @@ void PropertyEditor::update_tree() { } break; case Variant::DICTIONARY: { + Variant v = obj->get(p.name); + item->set_cell_mode(1, TreeItem::CELL_MODE_STRING); - item->set_editable(1, false); - item->set_text(1, obj->get(p.name).operator String()); + item->set_text(1, String("Dictionary{") + itos(v.call("size")) + "}"); + item->add_button(1, get_icon("EditResource", "EditorIcons")); + + if (show_type_icons) + item->set_icon(0, get_icon("DictionaryData", "EditorIcons")); } break; @@ -3416,7 +3423,9 @@ void PropertyEditor::update_tree() { type = p.hint_string; RES res = obj->get(p.name).operator RefPtr(); - + if (type.begins_with("RES:") && type != "RES:") { // Remote resources + res = ResourceLoader::load(type.substr(4, type.length())); + } Ref<EncodedObjectAsID> encoded = obj->get(p.name); //for debugger and remote tools if (encoded.is_valid()) { @@ -3427,6 +3436,7 @@ void PropertyEditor::update_tree() { item->set_editable(1, true); } else if (obj->get(p.name).get_type() == Variant::NIL || res.is_null()) { + item->set_text(1, "<null>"); item->set_icon(1, Ref<Texture>()); item->set_custom_as_button(1, false); @@ -3585,7 +3595,7 @@ void PropertyEditor::_edit_set(const String &p_name, const Variant &p_value, boo } } - if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(obj)) { //kind of hacky + if (!undo_redo || Object::cast_to<ArrayPropertyEdit>(obj) || Object::cast_to<DictionaryPropertyEdit>(obj)) { //kind of hacky obj->set(p_name, p_value); if (p_refresh_all) @@ -3983,8 +3993,20 @@ void PropertyEditor::_edit_button(Object *p_item, int p_column, int p_button) { Ref<ArrayPropertyEdit> ape = memnew(ArrayPropertyEdit); ape->edit(obj, n, ht, Variant::Type(t)); - EditorNode::get_singleton()->push_item(ape.ptr()); + + } else if (t == Variant::DICTIONARY) { + + Variant v = obj->get(n); + + if (v.get_type() != t) { + Variant::CallError ce; + v = Variant::construct(Variant::Type(t), NULL, 0, ce); + } + + Ref<DictionaryPropertyEdit> dpe = memnew(DictionaryPropertyEdit); + dpe->edit(obj, n); + EditorNode::get_singleton()->push_item(dpe.ptr()); } } } diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index e7e57a7079..1d2647badc 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1853,6 +1853,8 @@ void SceneTreeDock::_local_tree_selected() { remote_tree->hide(); edit_remote->set_pressed(false); edit_local->set_pressed(true); + + _node_selected(); } void SceneTreeDock::_bind_methods() { diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index bc2423fffd..2a3e47b2a6 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -116,7 +116,7 @@ class ScriptEditorDebuggerInspectedObject : public Object { protected: bool _set(const StringName &p_name, const Variant &p_value) { - if (!prop_values.has(p_name)) + if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/")) return false; emit_signal("value_edited", p_name, p_value); @@ -132,6 +132,7 @@ protected: r_ret = prop_values[p_name]; return true; } + void _get_property_list(List<PropertyInfo> *p_list) const { p_list->clear(); //sorry, no want category @@ -142,23 +143,52 @@ protected: static void _bind_methods() { + ClassDB::bind_method(D_METHOD("get_title"), &ScriptEditorDebuggerInspectedObject::get_title); + ClassDB::bind_method(D_METHOD("get_variant"), &ScriptEditorDebuggerInspectedObject::get_variant); + ClassDB::bind_method(D_METHOD("clear"), &ScriptEditorDebuggerInspectedObject::clear); + ClassDB::bind_method(D_METHOD("get_remote_object_id"), &ScriptEditorDebuggerInspectedObject::get_remote_object_id); + ADD_SIGNAL(MethodInfo("value_edited")); } public: - ObjectID last_edited_id; + String type_name; + ObjectID remote_object_id; List<PropertyInfo> prop_list; Map<StringName, Variant> prop_values; + ObjectID get_remote_object_id() { + return remote_object_id; + } + + String get_title() { + if (remote_object_id) + return TTR("Remote ") + String(type_name) + ": " + itos(remote_object_id); + else + return "<null>"; + } + Variant get_variant(const StringName &p_name) { + + Variant var; + _get(p_name, var); + return var; + } + + void clear() { + + prop_list.clear(); + prop_values.clear(); + } void update() { _change_notify(); } - void update_single(const char *p_prop) { _change_notify(p_prop); } - ScriptEditorDebuggerInspectedObject() { last_edited_id = 0; } + ScriptEditorDebuggerInspectedObject() { + remote_object_id = 0; + } }; void ScriptEditorDebugger::debug_next() { @@ -297,7 +327,6 @@ Size2 ScriptEditorDebugger::get_minimum_size() const { void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_data) { if (p_msg == "debug_enter") { - Array msg; msg.push_back("get_stack_dump"); ppeer->put_var(msg); @@ -315,12 +344,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da if (error != "") { tabs->set_current_tab(0); } - profiler->set_enabled(false); - EditorNode::get_singleton()->get_pause_button()->set_pressed(true); - EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + _clear_remote_objects(); } else if (p_msg == "debug_exit") { @@ -337,9 +364,8 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da //tabs->set_current_tab(0); profiler->set_enabled(true); profiler->disable_seeking(); - + inspector->edit(NULL); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); - } else if (p_msg == "message:click_ctrl") { clicked_ctrl->set_text(p_data[0]); @@ -399,55 +425,57 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da le_set->set_disabled(false); } else if (p_msg == "message:inspect_object") { + ScriptEditorDebuggerInspectedObject *debugObj = NULL; + ObjectID id = p_data[0]; String type = p_data[1]; - Variant path = p_data[2]; //what to do yet, i don't know - int prop_count = p_data[3]; - - int idx = 4; + Array properties = p_data[2]; - if (inspected_object->last_edited_id != id) { - inspected_object->prop_list.clear(); - inspected_object->prop_values.clear(); + bool is_new_object = false; + if (remote_objects.has(id)) { + debugObj = remote_objects[id]; + } else { + debugObj = memnew(ScriptEditorDebuggerInspectedObject); + debugObj->remote_object_id = id; + debugObj->type_name = type; + remote_objects[id] = debugObj; + is_new_object = true; + debugObj->connect("value_edited", this, "_scene_tree_property_value_edited"); } - for (int i = 0; i < prop_count; i++) { + for (int i = 0; i < properties.size(); i++) { + + Array prop = properties[i]; + if (prop.size() != 6) + continue; PropertyInfo pinfo; - pinfo.name = p_data[idx++]; - pinfo.type = Variant::Type(int(p_data[idx++])); - pinfo.hint = PropertyHint(int(p_data[idx++])); - pinfo.hint_string = p_data[idx++]; - if (pinfo.name.begins_with("*")) { - pinfo.name = pinfo.name.substr(1, pinfo.name.length()); - pinfo.usage = PROPERTY_USAGE_CATEGORY; - } else { - pinfo.usage = PROPERTY_USAGE_EDITOR; + pinfo.name = prop[0]; + pinfo.type = Variant::Type(int(prop[1])); + pinfo.hint = PropertyHint(int(prop[2])); + pinfo.hint_string = prop[3]; + pinfo.usage = PropertyUsageFlags(int(prop[4])); + Variant var = prop[5]; + + String hint_string = pinfo.hint_string; + if (hint_string.begins_with("RES:") && hint_string != "RES:") { + String path = hint_string.substr(4, hint_string.length()); + var = ResourceLoader::load(path); } - if (inspected_object->last_edited_id != id) { + if (is_new_object) { //don't update.. it's the same, instead refresh - inspected_object->prop_list.push_back(pinfo); + debugObj->prop_list.push_back(pinfo); } - inspected_object->prop_values[pinfo.name] = p_data[idx++]; - - if (inspected_object->last_edited_id == id) { - //same, just update value, don't rebuild - inspected_object->update_single(pinfo.name.ascii().get_data()); - } + debugObj->prop_values[pinfo.name] = var; } - if (inspected_object->last_edited_id != id) { - //only if different - inspected_object->update(); + if (editor->get_editor_history()->get_current() != debugObj->get_instance_id()) { + editor->push_item(debugObj, ""); + } else { + debugObj->update(); } - - inspected_object->last_edited_id = id; - - tabs->set_current_tab(inspect_info->get_index()); - inspect_properties->edit(inspected_object); - } else if (p_msg == "message:video_mem") { vmem_tree->clear(); @@ -502,7 +530,6 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da int ofs = 0; int mcount = p_data[ofs]; - ofs++; for (int i = 0; i < mcount; i++) { @@ -521,12 +548,34 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da v = s.get_slice(":", 1).to_int(); } - variables->add_property("members/" + n, v, h, hs); + variables->add_property("Locals/" + n, v, h, hs); } - ofs += mcount * 2; + ofs += mcount * 2; mcount = p_data[ofs]; + ofs++; + for (int i = 0; i < mcount; i++) { + + String n = p_data[ofs + i * 2 + 0]; + Variant v = p_data[ofs + i * 2 + 1]; + PropertyHint h = PROPERTY_HINT_NONE; + String hs = String(); + + if (n.begins_with("*")) { + + n = n.substr(1, n.length()); + h = PROPERTY_HINT_OBJECT_ID; + String s = v; + s = s.replace("[", ""); + hs = s.get_slice(":", 0); + v = s.get_slice(":", 1).to_int(); + } + + variables->add_property("Members/" + n, v, h, hs); + } + ofs += mcount * 2; + mcount = p_data[ofs]; ofs++; for (int i = 0; i < mcount; i++) { @@ -545,7 +594,7 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da v = s.get_slice(":", 1).to_int(); } - variables->add_property("locals/" + n, v, h, hs); + variables->add_property("Globals/" + n, v, h, hs); } variables->update(); @@ -1101,6 +1150,8 @@ void ScriptEditorDebugger::start() { EditorNode::get_log()->add_message(String("Error listening on port ") + itos(remote_port), true); return; } + + EditorNode::get_singleton()->get_scene_tree_dock()->show_remote_tree(); set_process(true); } @@ -1133,11 +1184,11 @@ void ScriptEditorDebugger::stop() { le_set->set_disabled(true); profiler->set_enabled(true); - inspect_properties->edit(NULL); inspect_scene_tree->clear(); EditorNode::get_singleton()->get_pause_button()->set_pressed(false); EditorNode::get_singleton()->get_pause_button()->set_disabled(true); + EditorNode::get_singleton()->get_scene_tree_dock()->hide_remote_tree(); if (hide_on_stop) { if (is_visible_in_tree()) @@ -1604,6 +1655,24 @@ void ScriptEditorDebugger::_paused() { } } +void ScriptEditorDebugger::_set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj) { + + if (remote_objects.has(p_id)) + memdelete(remote_objects[p_id]); + remote_objects[p_id] = p_obj; +} + +void ScriptEditorDebugger::_clear_remote_objects() { + + for (Map<ObjectID, ScriptEditorDebuggerInspectedObject *>::Element *E = remote_objects.front(); E; E = E->next()) { + if (editor->get_editor_history()->get_current() == E->value()->get_instance_id()) { + editor->push_item(NULL); + } + memdelete(E->value()); + } + remote_objects.clear(); +} + void ScriptEditorDebugger::_bind_methods() { ClassDB::bind_method(D_METHOD("_stack_dump_frame_selected"), &ScriptEditorDebugger::_stack_dump_frame_selected); @@ -1649,6 +1718,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { ppeer = Ref<PacketPeerStream>(memnew(PacketPeerStream)); ppeer->set_input_buffer_max_size(1024 * 1024 * 8); //8mb should be enough editor = p_editor; + editor->get_property_editor()->connect("object_id_selected", this, "_scene_tree_property_select_object"); tabs = memnew(TabContainer); tabs->set_tab_align(TabContainer::ALIGN_LEFT); @@ -1761,41 +1831,18 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { tabs->add_child(error_split); } - { // inquire - - inspect_info = memnew(HSplitContainer); - inspect_info->set_name(TTR("Remote Inspector")); - tabs->add_child(inspect_info); - - VBoxContainer *info_left = memnew(VBoxContainer); - info_left->set_h_size_flags(SIZE_EXPAND_FILL); - inspect_info->add_child(info_left); + { // remote scene tree inspect_scene_tree = memnew(Tree); - info_left->add_margin_child(TTR("Live Scene Tree:"), inspect_scene_tree, true); + EditorNode::get_singleton()->get_scene_tree_dock()->add_remote_tree_editor(inspect_scene_tree); + inspect_scene_tree->set_v_size_flags(SIZE_EXPAND_FILL); inspect_scene_tree->connect("cell_selected", this, "_scene_tree_selected"); inspect_scene_tree->connect("item_collapsed", this, "_scene_tree_folded"); - // - - VBoxContainer *info_right = memnew(VBoxContainer); - info_right->set_h_size_flags(SIZE_EXPAND_FILL); - inspect_info->add_child(info_right); - - inspect_properties = memnew(PropertyEditor); - inspect_properties->hide_top_label(); - inspect_properties->set_show_categories(true); - inspect_properties->connect("object_id_selected", this, "_scene_tree_property_select_object"); - - info_right->add_margin_child(TTR("Remote Object Properties: "), inspect_properties, true); - inspect_scene_tree_timeout = EDITOR_DEF("debugger/scene_tree_refresh_interval", 1.0); inspect_edited_object_timeout = EDITOR_DEF("debugger/remote_inspect_refresh_interval", 0.2); inspected_object_id = 0; updating_scene_tree = false; - - inspected_object = memnew(ScriptEditorDebuggerInspectedObject); - inspected_object->connect("value_edited", this, "_scene_tree_property_value_edited"); } { //profiler @@ -1952,5 +1999,5 @@ ScriptEditorDebugger::~ScriptEditorDebugger() { ppeer->set_stream_peer(Ref<StreamPeer>()); server->stop(); - memdelete(inspected_object); + _clear_remote_objects(); } diff --git a/editor/script_editor_debugger.h b/editor/script_editor_debugger.h index d18a625eef..dc851dd575 100644 --- a/editor/script_editor_debugger.h +++ b/editor/script_editor_debugger.h @@ -72,19 +72,18 @@ class ScriptEditorDebugger : public Control { Button *le_set; Button *le_clear; - Tree *inspect_scene_tree; - HSplitContainer *inspect_info; - PropertyEditor *inspect_properties; + bool updating_scene_tree; float inspect_scene_tree_timeout; float inspect_edited_object_timeout; ObjectID inspected_object_id; - ScriptEditorDebuggerInspectedObject *inspected_object; - bool updating_scene_tree; + ScriptEditorDebuggerVariables *variables; + Map<ObjectID, ScriptEditorDebuggerInspectedObject *> remote_objects; Set<ObjectID> unfold_cache; HSplitContainer *error_split; ItemList *error_list; ItemList *error_stack; + Tree *inspect_scene_tree; int error_count; int last_error_count; @@ -96,7 +95,6 @@ class ScriptEditorDebugger : public Control { TabContainer *tabs; Label *reason; - ScriptEditorDebuggerVariables *variables; Button *step; Button *next; @@ -174,6 +172,9 @@ class ScriptEditorDebugger : public Control { void _paused(); + void _set_remote_object(ObjectID p_id, ScriptEditorDebuggerInspectedObject *p_obj); + void _clear_remote_objects(); + protected: void _notification(int p_what); static void _bind_methods(); diff --git a/modules/bullet/space_bullet.cpp b/modules/bullet/space_bullet.cpp index e4d049b00d..853906063b 100644 --- a/modules/bullet/space_bullet.cpp +++ b/modules/bullet/space_bullet.cpp @@ -175,13 +175,13 @@ bool BulletPhysicsDirectSpaceState::cast_motion(const RID &p_shape, const Transf space->dynamicsWorld->convexSweepTest(bt_convex_shape, bt_xform_from, bt_xform_to, btResult, 0.002); - if (r_info) { - if (btResult.hasHit()) { + if (btResult.hasHit()) { + p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; + if (r_info) { if (btCollisionObject::CO_RIGID_BODY == btResult.m_hitCollisionObject->getInternalType()) { B_TO_G(static_cast<const btRigidBody *>(btResult.m_hitCollisionObject)->getVelocityInLocalPoint(btResult.m_hitPointWorld), r_info->linear_velocity); } CollisionObjectBullet *collision_object = static_cast<CollisionObjectBullet *>(btResult.m_hitCollisionObject->getUserPointer()); - p_closest_safe = p_closest_unsafe = btResult.m_closestHitFraction; B_TO_G(btResult.m_hitPointWorld, r_info->point); B_TO_G(btResult.m_hitNormalWorld, r_info->normal); r_info->rid = collision_object->get_self(); diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 55ea8a5f24..41a810ff00 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -100,7 +100,7 @@ GDScriptInstance *GDScript::_create_instance(const Variant **p_args, int p_argco #endif instance->owner->set_script_instance(instance); -/* STEP 2, INITIALIZE AND CONSRTUCT */ + /* STEP 2, INITIALIZE AND CONSRTUCT */ #ifndef NO_THREADS GDScriptLanguage::singleton->lock->lock(); @@ -615,6 +615,23 @@ ScriptLanguage *GDScript::get_language() const { return GDScriptLanguage::get_singleton(); } +void GDScript::get_constants(Map<StringName, Variant> *p_constants) { + + if (p_constants) { + for (Map<StringName, Variant>::Element *E = constants.front(); E; E = E->next()) { + (*p_constants)[E->key()] = E->value(); + } + } +} + +void GDScript::get_members(Set<StringName> *p_members) { + if (p_members) { + for (Set<StringName>::Element *E = members.front(); E; E = E->next()) { + p_members->insert(E->get()); + } + } +} + Variant GDScript::call(const StringName &p_method, const Variant **p_args, int p_argcount, Variant::CallError &r_error) { GDScript *top = this; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 3f6f431938..6e5d59ad0e 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -198,6 +198,9 @@ public: return -1; } + virtual void get_constants(Map<StringName, Variant> *p_constants); + virtual void get_members(Set<StringName> *p_members); + GDScript(); ~GDScript(); }; @@ -219,7 +222,7 @@ class GDScriptInstance : public ScriptInstance { void _ml_call_reversed(GDScript *sptr, const StringName &p_method, const Variant **p_args, int p_argcount); public: - _FORCE_INLINE_ Object *get_owner() { return owner; } + virtual Object *get_owner() { return owner; } virtual bool set(const StringName &p_name, const Variant &p_value); virtual bool get(const StringName &p_name, Variant &r_ret) const; @@ -407,7 +410,8 @@ public: virtual String debug_get_stack_level_source(int p_level) const; virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); - virtual void debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); + virtual ScriptInstance *debug_get_stack_level_instance(int p_level); + virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1); virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1); virtual void reload_all_scripts(); diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index a74b8a8483..5a76acea6e 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -33,7 +33,7 @@ #include "gdscript_compiler.h" #include "global_constants.h" #include "os/file_access.h" -#include "project_settings.h" +#include "core/engine.h" #ifdef TOOLS_ENABLED #include "editor/editor_file_system.h" @@ -280,10 +280,62 @@ void GDScriptLanguage::debug_get_stack_level_members(int p_level, List<String> * p_values->push_back(instance->debug_get_member_by_index(E->get().index)); } } -void GDScriptLanguage::debug_get_globals(List<String> *p_locals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { - //no globals are really reachable in gdscript +ScriptInstance *GDScriptLanguage::debug_get_stack_level_instance(int p_level) { + + ERR_FAIL_COND_V(_debug_parse_err_line >= 0, NULL); + ERR_FAIL_INDEX_V(p_level, _debug_call_stack_pos, NULL); + + int l = _debug_call_stack_pos - p_level - 1; + ScriptInstance *instance = _call_stack[l].instance; + + return instance; } + +void GDScriptLanguage::debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems, int p_max_depth) { + + const Map<StringName, int> &name_idx = GDScriptLanguage::get_singleton()->get_global_map(); + const Variant *globals = GDScriptLanguage::get_singleton()->get_global_array(); + + List<Pair<String, Variant> > cinfo; + get_public_constants(&cinfo); + + for (const Map<StringName, int>::Element *E = name_idx.front(); E; E = E->next()) { + + if (ClassDB::class_exists(E->key()) || Engine::get_singleton()->has_singleton(E->key())) + continue; + + bool is_script_constant = false; + for (List<Pair<String, Variant> >::Element *CE = cinfo.front(); CE; CE = CE->next()) { + if (CE->get().first == E->key()) { + is_script_constant = true; + break; + } + } + if (is_script_constant) + continue; + + const Variant &var = globals[E->value()]; + if (Object *obj = var) { + if (Object::cast_to<GDScriptNativeClass>(obj)) + continue; + } + + bool skip = false; + for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) { + if (E->key() == GlobalConstants::get_global_constant_name(i)) { + skip = true; + break; + } + } + if (skip) + continue; + + p_globals->push_back(E->key()); + p_values->push_back(var); + } +} + String GDScriptLanguage::debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems, int p_max_depth) { if (_debug_parse_err_line >= 0) @@ -1743,7 +1795,7 @@ static void _find_type_arguments(GDScriptCompletionContext &context, const GDScr } } else { -//regular method + //regular method #if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED) if (p_argidx < m->get_argument_count()) { diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp index e9e9dcc859..5e4dedcb48 100644 --- a/scene/gui/item_list.cpp +++ b/scene/gui/item_list.cpp @@ -525,6 +525,11 @@ void ItemList::_gui_input(const Ref<InputEvent> &p_event) { return; } + if (mb->get_button_index() == BUTTON_RIGHT) { + emit_signal("rmb_clicked", mb->get_position()); + + return; + } } if (mb.is_valid() && mb->get_button_index() == BUTTON_WHEEL_UP && mb->is_pressed()) { @@ -1397,6 +1402,7 @@ void ItemList::_bind_methods() { ADD_SIGNAL(MethodInfo("item_rmb_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::VECTOR2, "at_position"))); ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "selected"))); ADD_SIGNAL(MethodInfo("item_activated", PropertyInfo(Variant::INT, "index"))); + ADD_SIGNAL(MethodInfo("rmb_clicked", PropertyInfo(Variant::VECTOR2, "at_position"))); GLOBAL_DEF("gui/timers/incremental_search_max_interval_msec", 2000); } diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c9af7eed0d..21842d4d58 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1238,7 +1238,9 @@ void TextEdit::_notification(int p_what) { char_ofs += char_w; if (j == str.length() - 1 && is_folded(line)) { - cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin, ofs_y), Color(1, 1, 1, 1), true); + int yofs = (get_row_height() - cache.folded_eol_icon->get_height()) / 2; + int xofs = cache.folded_eol_icon->get_width() / 2; + cache.folded_eol_icon->draw(ci, Point2(char_ofs + char_margin + xofs, ofs_y + yofs), Color(1, 1, 1, 1)); } } @@ -3937,7 +3939,7 @@ void TextEdit::_update_caches() { cache.tab_icon = get_icon("tab"); cache.folded_icon = get_icon("GuiTreeArrowRight", "EditorIcons"); cache.can_fold_icon = get_icon("GuiTreeArrowDown", "EditorIcons"); - cache.folded_eol_icon = get_icon("GuiTabMenu", "EditorIcons"); + cache.folded_eol_icon = get_icon("GuiEllipsis", "EditorIcons"); text.set_font(cache.font); } diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index 08a0cfa269..7551485919 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -504,6 +504,8 @@ public: BIND3(instance_set_surface_material, RID, int, RID) BIND2(instance_set_visible, RID, bool) + BIND2(instance_set_custom_aabb, RID, AABB) + BIND2(instance_attach_skeleton, RID, RID) BIND2(instance_set_exterior, RID, bool) diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 4febd1a61b..5b1eb8357d 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -587,6 +587,36 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) { } } +inline bool is_geometry_instance(VisualServer::InstanceType p_type) { + return p_type == VS::INSTANCE_MESH || p_type == VS::INSTANCE_MULTIMESH || p_type == VS::INSTANCE_PARTICLES || p_type == VS::INSTANCE_IMMEDIATE; +} + +void VisualServerScene::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { + + Instance *instance = instance_owner.get(p_instance); + ERR_FAIL_COND(!instance); + ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); + + if(p_aabb != AABB()) { + + // Set custom AABB + if (instance->custom_aabb == NULL) + instance->custom_aabb = memnew(AABB); + *instance->custom_aabb = p_aabb; + + } else { + + // Clear custom AABB + if (instance->custom_aabb != NULL) { + memdelete(instance->custom_aabb); + instance->custom_aabb = NULL; + } + } + + if (instance->scenario) + _instance_queue_update(instance, true, false); +} + void VisualServerScene::instance_attach_skeleton(RID p_instance, RID p_skeleton) { Instance *instance = instance_owner.get(p_instance); @@ -828,23 +858,35 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { } break; case VisualServer::INSTANCE_MESH: { - new_aabb = VSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton); + if (p_instance->custom_aabb) + new_aabb = *p_instance->custom_aabb; + else + new_aabb = VSG::storage->mesh_get_aabb(p_instance->base, p_instance->skeleton); } break; case VisualServer::INSTANCE_MULTIMESH: { - new_aabb = VSG::storage->multimesh_get_aabb(p_instance->base); + if (p_instance->custom_aabb) + new_aabb = *p_instance->custom_aabb; + else + new_aabb = VSG::storage->multimesh_get_aabb(p_instance->base); } break; case VisualServer::INSTANCE_IMMEDIATE: { - new_aabb = VSG::storage->immediate_get_aabb(p_instance->base); + if (p_instance->custom_aabb) + new_aabb = *p_instance->custom_aabb; + else + new_aabb = VSG::storage->immediate_get_aabb(p_instance->base); } break; case VisualServer::INSTANCE_PARTICLES: { - new_aabb = VSG::storage->particles_get_aabb(p_instance->base); + if (p_instance->custom_aabb) + new_aabb = *p_instance->custom_aabb; + else + new_aabb = VSG::storage->particles_get_aabb(p_instance->base); } break; case VisualServer::INSTANCE_LIGHT: { @@ -866,6 +908,7 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) { default: {} } + // <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs if (p_instance->extra_margin) new_aabb.grow_by(p_instance->extra_margin); diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h index 2738fa058d..d075be76ca 100644 --- a/servers/visual/visual_server_scene.h +++ b/servers/visual/visual_server_scene.h @@ -197,6 +197,7 @@ public: AABB aabb; AABB transformed_aabb; + AABB *custom_aabb; // <Zylann> would using aabb directly with a bool be better? float extra_margin; uint32_t object_ID; @@ -251,12 +252,16 @@ public: last_frame_pass = 0; version = 1; base_data = NULL; + + custom_aabb = NULL; } ~Instance() { if (base_data) memdelete(base_data); + if (custom_aabb) + memdelete(custom_aabb); } }; @@ -460,6 +465,8 @@ public: virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material); virtual void instance_set_visible(RID p_instance, bool p_visible); + virtual void instance_set_custom_aabb(RID p_insatnce, AABB aabb); + virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton); virtual void instance_set_exterior(RID p_instance, bool p_enabled); diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 509b77cf9c..e120eb5ad3 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -424,6 +424,7 @@ public: FUNC3(instance_set_blend_shape_weight, RID, int, float) FUNC3(instance_set_surface_material, RID, int, RID) FUNC2(instance_set_visible, RID, bool) + FUNC2(instance_set_custom_aabb, RID, AABB) FUNC2(instance_attach_skeleton, RID, RID) FUNC2(instance_set_exterior, RID, bool) diff --git a/servers/visual_server.h b/servers/visual_server.h index 3edde7ec85..c4b1583009 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -753,6 +753,8 @@ public: virtual void instance_set_surface_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; + virtual void instance_set_custom_aabb(RID p_instance, AABB aabb) = 0; + virtual void instance_attach_skeleton(RID p_instance, RID p_skeleton) = 0; virtual void instance_set_exterior(RID p_instance, bool p_enabled) = 0; |