diff options
77 files changed, 3090 insertions, 1162 deletions
diff --git a/.gitignore b/.gitignore index 35fadafbda..6db75f2324 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ platform/android/java/build.gradle platform/android/java/AndroidManifest.xml platform/android/java/libs/* platform/android/java/assets +platform/android/java/.idea/* +platform/android/java/*.iml # General c++ generated files *.lib @@ -44,6 +46,7 @@ gmon.out # QT project files *.config *.creator +*.creator.* *.files *.includes diff --git a/core/dictionary.cpp b/core/dictionary.cpp index ba0de95861..d68411a572 100644 --- a/core/dictionary.cpp +++ b/core/dictionary.cpp @@ -50,6 +50,32 @@ void Dictionary::get_key_list(List<Variant> *p_keys) const { } } +Variant Dictionary::get_key_at_index(int p_index) const { + + int index = 0; + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + if (index == p_index) { + return E.key(); + } + index++; + } + + return Variant(); +} + +Variant Dictionary::get_value_at_index(int p_index) const { + + int index = 0; + for (OrderedHashMap<Variant, Variant, VariantHasher, VariantComparator>::Element E = _p->variant_map.front(); E; E = E.next()) { + if (index == p_index) { + return E.value(); + } + index++; + } + + return Variant(); +} + Variant &Dictionary::operator[](const Variant &p_key) { return _p->variant_map[p_key]; diff --git a/core/dictionary.h b/core/dictionary.h index 9eef265d5b..84a5cafe1d 100644 --- a/core/dictionary.h +++ b/core/dictionary.h @@ -47,6 +47,8 @@ class Dictionary { public: void get_key_list(List<Variant> *p_keys) const; + Variant get_key_at_index(int p_index) const; + Variant get_value_at_index(int p_index) const; Variant &operator[](const Variant &p_key); const Variant &operator[](const Variant &p_key) const; diff --git a/core/ustring.cpp b/core/ustring.cpp index 85b7a16e6a..51f05468e2 100644 --- a/core/ustring.cpp +++ b/core/ustring.cpp @@ -753,6 +753,46 @@ Vector<String> String::split(const String &p_splitter, bool p_allow_empty, int p return ret; } +Vector<String> String::rsplit(const String &p_splitter, bool p_allow_empty, int p_maxsplit) const { + + Vector<String> ret; + const int len = length(); + int from = len; + + while (true) { + + int end = rfind(p_splitter, from); + if (end < 0) + end = 0; + + if (p_allow_empty || (end < from)) { + const String str = substr(end > 0 ? end + p_splitter.length() : end, end > 0 ? from - end : from + 2); + + if (p_maxsplit <= 0) { + ret.push_back(str); + } else if (p_maxsplit > 0) { + + // Put rest of the string and leave cycle. + if (p_maxsplit == ret.size()) { + ret.push_back(substr(0, from + 2)); + break; + } + + // Otherwise, push items until positive limit is reached. + ret.push_back(str); + } + } + + if (end == 0) + break; + + from = end - p_splitter.length(); + } + + ret.invert(); + return ret; +} + Vector<float> String::split_floats(const String &p_splitter, bool p_allow_empty) const { Vector<float> ret; diff --git a/core/ustring.h b/core/ustring.h index 1ed694bb80..b57e9629d9 100644 --- a/core/ustring.h +++ b/core/ustring.h @@ -172,6 +172,7 @@ public: String get_slicec(CharType p_splitter, int p_slice) const; Vector<String> split(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; + Vector<String> rsplit(const String &p_splitter, bool p_allow_empty = true, int p_maxsplit = 0) const; Vector<String> split_spaces() const; Vector<float> split_floats(const String &p_splitter, bool p_allow_empty = true) const; Vector<float> split_floats_mk(const Vector<String> &p_splitters, bool p_allow_empty = true) const; diff --git a/core/variant_call.cpp b/core/variant_call.cpp index 4e883d496f..4158c2a60e 100644 --- a/core/variant_call.cpp +++ b/core/variant_call.cpp @@ -257,6 +257,7 @@ struct _VariantCall { VCALL_LOCALMEM2R(String, insert); VCALL_LOCALMEM0R(String, capitalize); VCALL_LOCALMEM3R(String, split); + VCALL_LOCALMEM3R(String, rsplit); VCALL_LOCALMEM2R(String, split_floats); VCALL_LOCALMEM0R(String, to_upper); VCALL_LOCALMEM0R(String, to_lower); @@ -1469,6 +1470,7 @@ void register_variant_methods() { ADDFUNC2R(STRING, STRING, String, insert, INT, "position", STRING, "what", varray()); ADDFUNC0R(STRING, STRING, String, capitalize, varray()); ADDFUNC3R(STRING, POOL_STRING_ARRAY, String, split, STRING, "divisor", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0)); + ADDFUNC3R(STRING, POOL_STRING_ARRAY, String, rsplit, STRING, "divisor", BOOL, "allow_empty", INT, "maxsplit", varray(true, 0)); ADDFUNC2R(STRING, POOL_REAL_ARRAY, String, split_floats, STRING, "divisor", BOOL, "allow_empty", varray(true)); ADDFUNC0R(STRING, STRING, String, to_upper, varray()); diff --git a/doc/classes/String.xml b/doc/classes/String.xml index 83fb76f287..a55e184474 100644 --- a/doc/classes/String.xml +++ b/doc/classes/String.xml @@ -688,6 +688,20 @@ If [code]maxsplit[/code] is given, at most maxsplit number of splits occur, and the remainder of the string is returned as the final element of the list (thus, the list will have at most maxsplit+1 elements) </description> </method> + <method name="rsplit"> + <return type="PoolStringArray"> + </return> + <argument index="0" name="divisor" type="String"> + </argument> + <argument index="1" name="allow_empty" type="bool" default="True"> + </argument> + <argument index="2" name="maxsplit" type="int" default="0"> + </argument> + <description> + Splits the string by a [code]divisor[/code] string and returns an array of the substrings, starting from right. Example "One,Two,Three" will return ["One","Two","Three"] if split by ",". + If [code]maxsplit[/code] is specified, then it is number of splits to do, default is 0 which splits all the items. + </description> + </method> <method name="split_floats"> <return type="PoolRealArray"> </return> diff --git a/doc/classes/TextureRect.xml b/doc/classes/TextureRect.xml index 7a4208ccea..95afc5d281 100644 --- a/doc/classes/TextureRect.xml +++ b/doc/classes/TextureRect.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="TextureRect" inherits="Control" category="Core" version="3.1"> <brief_description> - Draws a sprite or a texture inside a User Interface. The texture can tile or not. + Control for drawing textures. </brief_description> <description> - Use TextureRect to draw icons and sprites in your User Interfaces. To create panels and menu boxes, take a look at [NinePatchFrame]. Its Stretch Mode property controls the texture's scale and placement. It can scale, tile and stay centered inside its bounding rectangle. TextureRect is one of the 5 most common nodes to create game UI. + Used to draw icons and sprites in a user interface. The texture's placement can be controlled with the [member stretch_mode] property. It can scale, tile, or stay centered inside its bounding rectangle. </description> <tutorials> </tutorials> @@ -14,10 +14,10 @@ </methods> <members> <member name="expand" type="bool" setter="set_expand" getter="has_expand"> - If [code]true[/code], the texture scales to fit its bounding rectangle. Default value: [code]false[/code]. + If [code]true[/code] the texture scales to fit its bounding rectangle. Default value: [code]false[/code]. </member> <member name="stretch_mode" type="int" setter="set_stretch_mode" getter="get_stretch_mode" enum="TextureRect.StretchMode"> - Controls the texture's behavior when you resize the node's bounding rectangle. Set it to one of the [code]STRETCH_*[/code] constants. See the constants to learn more. + Controls the texture's behavior when resizing the node's bounding rectangle. See [enum StretchMode]. </member> <member name="texture" type="Texture" setter="set_texture" getter="get_texture"> The node's [Texture] resource. diff --git a/doc/classes/VideoPlayer.xml b/doc/classes/VideoPlayer.xml index d2639590a1..9ffa3aa52b 100644 --- a/doc/classes/VideoPlayer.xml +++ b/doc/classes/VideoPlayer.xml @@ -1,10 +1,10 @@ <?xml version="1.0" encoding="UTF-8" ?> <class name="VideoPlayer" inherits="Control" category="Core" version="3.1"> <brief_description> - Control to play video files. + Control for playing video streams. </brief_description> <description> - This control has the ability to play video streams. The only format accepted is the OGV Theora, so any other format must be converted before using in a project. + Control node for playing video streams. Supported formats are WebM and OGV Theora. </description> <tutorials> </tutorials> @@ -15,51 +15,56 @@ <return type="String"> </return> <description> - Get the name of the video stream. + Returns the video stream's name. </description> </method> <method name="get_video_texture"> <return type="Texture"> </return> <description> - Get the current frame of the video as a [Texture]. + Returns the current frame as a [Texture]. </description> </method> <method name="is_playing" qualifiers="const"> <return type="bool"> </return> <description> - Get whether or not the video is playing. + Returns [code]true[/code] if the video is playing. </description> </method> <method name="play"> <return type="void"> </return> <description> - Start the video playback. + Starts the video playback. </description> </method> <method name="stop"> <return type="void"> </return> <description> - Stop the video playback. + Stops the video playback. </description> </method> </methods> <members> <member name="audio_track" type="int" setter="set_audio_track" getter="get_audio_track"> + The embedded audio track to play. </member> <member name="autoplay" type="bool" setter="set_autoplay" getter="has_autoplay"> + If [code]true[/code] playback starts when the scene loads. Default value: [code]false[/code]. </member> <member name="buffering_msec" type="int" setter="set_buffering_msec" getter="get_buffering_msec"> - The amount of milliseconds to store in buffer while playing. + Amount of time in milliseconds to store in buffer while playing. </member> <member name="bus" type="String" setter="set_bus" getter="get_bus"> + Audio bus to use for sound playback. </member> <member name="expand" type="bool" setter="set_expand" getter="has_expand"> + If [code]true[/code] the video scales to the control size. Default value: [code]true[/code]. </member> <member name="paused" type="bool" setter="set_paused" getter="is_paused"> + If [code]true[/code] the video is paused. </member> <member name="stream" type="VideoStream" setter="set_stream" getter="get_stream"> </member> @@ -67,14 +72,16 @@ The current position of the stream, in seconds. </member> <member name="volume" type="float" setter="set_volume" getter="get_volume"> - The volume of the audio track as a linear value. + Audio volume as a linear value. </member> <member name="volume_db" type="float" setter="set_volume_db" getter="get_volume_db"> + Audio volume in dB. </member> </members> <signals> <signal name="finished"> <description> + Emitted when playback is finished. </description> </signal> </signals> diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index 4626a5ed3c..ab48e682d6 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -346,7 +346,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c if (OS::get_singleton()->is_layered_allowed()) { if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#ifdef WINDOWS_ENABLED +#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); if (data) { @@ -401,7 +401,7 @@ void RasterizerGLES2::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#ifdef WINDOWS_ENABLED +#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); if (data) { diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index 12e29827b0..1abdaa5f80 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -335,7 +335,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c if (OS::get_singleton()->is_layered_allowed()) { if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#ifdef WINDOWS_ENABLED +#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); if (data) { @@ -392,7 +392,7 @@ void RasterizerGLES3::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) { -#ifdef WINDOWS_ENABLED +#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) Size2 wndsize = OS::get_singleton()->get_layered_buffer_size(); uint8_t *data = OS::get_singleton()->get_layered_buffer_data(); if (data) { diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 945df35456..85ae69f8b8 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5895,7 +5895,10 @@ void RasterizerStorageGLES3::update_particles() { tex = resources.white_tex; } break; } + } else if (t->proxy && t->proxy->tex_id) { + target = t->proxy->target; + tex = t->proxy->tex_id; } else { target = t->target; diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 708bff252a..de9203232c 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -52,6 +52,13 @@ void EditorAutoloadSettings::_notification(int p_what) { file_dialog->add_filter("*." + E->get()); } + + for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { + AutoLoadInfo &info = E->get(); + if (info.node && info.in_editor) { + get_tree()->get_root()->call_deferred("add_child", info.node); + } + } } } @@ -291,6 +298,36 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { autoload_add_name->set_text(p_path.get_file().get_basename()); } +Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { + RES res = ResourceLoader::load(p_path); + ERR_EXPLAIN("Can't autoload: " + p_path); + ERR_FAIL_COND_V(res.is_null(), NULL); + Node *n = NULL; + if (res->is_class("PackedScene")) { + Ref<PackedScene> ps = res; + n = ps->instance(); + } else if (res->is_class("Script")) { + Ref<Script> s = res; + StringName ibt = s->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "Node"); + ERR_EXPLAIN("Script does not inherit a Node: " + p_path); + ERR_FAIL_COND_V(!valid_type, NULL); + + Object *obj = ClassDB::instance(ibt); + + ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); + ERR_FAIL_COND_V(obj == NULL, NULL); + + n = Object::cast_to<Node>(obj); + n->set_script(s.get_ref_ptr()); + } + + ERR_EXPLAIN("Path in autoload not a node or script: " + p_path); + ERR_FAIL_COND_V(!n, NULL); + + return n; +} + void EditorAutoloadSettings::update_autoload() { if (updating_autoload) @@ -299,15 +336,11 @@ void EditorAutoloadSettings::update_autoload() { updating_autoload = true; Map<String, AutoLoadInfo> to_remove; - Map<String, AutoLoadInfo> to_remove_singleton; - List<AutoLoadInfo> to_add; - List<String> to_add_singleton; // Only for when the node is still the same + List<AutoLoadInfo *> to_add; for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { - to_remove.insert(E->get().name, E->get()); - if (E->get().is_singleton) { - to_remove_singleton.insert(E->get().name, E->get()); - } + AutoLoadInfo &info = E->get(); + to_remove.insert(info.name, info); } autoload_cache.clear(); @@ -331,11 +364,6 @@ void EditorAutoloadSettings::update_autoload() { if (name.empty()) continue; - AutoLoadInfo old_info; - if (to_remove.has(name)) { - old_info = to_remove[name]; - } - AutoLoadInfo info; info.is_singleton = path.begins_with("*"); @@ -347,28 +375,31 @@ void EditorAutoloadSettings::update_autoload() { info.path = path; info.order = ProjectSettings::get_singleton()->get_order(pi.name); - if (old_info.name == info.name) { + bool need_to_add = true; + if (to_remove.has(name)) { + AutoLoadInfo &old_info = to_remove[name]; if (old_info.path == info.path) { - // Still the same resource, check singleton status - to_remove.erase(name); - if (info.is_singleton) { - if (old_info.is_singleton) { - to_remove_singleton.erase(name); + // Still the same resource, check status + info.node = old_info.node; + if (info.node) { + Ref<Script> scr = info.node->get_script(); + info.in_editor = scr.is_valid() && scr->is_tool(); + if (info.is_singleton == old_info.is_singleton && info.in_editor == old_info.in_editor) { + to_remove.erase(name); + need_to_add = false; } else { - to_add_singleton.push_back(name); + info.node = NULL; } } - } else { - // Resource changed - to_add.push_back(info); } - } else { - // New autoload - to_add.push_back(info); } autoload_cache.push_back(info); + if (need_to_add) { + to_add.push_back(&(autoload_cache.back()->get())); + } + TreeItem *item = tree->create_item(root); item->set_text(0, name); item->set_editable(0, true); @@ -387,71 +418,54 @@ void EditorAutoloadSettings::update_autoload() { item->set_selectable(3, false); } - // Remove autoload constants - for (Map<String, AutoLoadInfo>::Element *E = to_remove_singleton.front(); E; E = E->next()) { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->remove_named_global_constant(E->get().name); - } - } - - // Remove obsolete nodes from the tree + // Remove deleted/changed autoloads for (Map<String, AutoLoadInfo>::Element *E = to_remove.front(); E; E = E->next()) { AutoLoadInfo &info = E->get(); - Node *al = get_node("/root/" + info.name); - ERR_CONTINUE(!al); - get_tree()->get_root()->remove_child(al); - memdelete(al); - } + if (info.is_singleton) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->remove_named_global_constant(info.name); + } + } + if (info.in_editor) { + ERR_CONTINUE(!info.node); + get_tree()->get_root()->remove_child(info.node); + } - // Register new singletons already in the tree - for (List<String>::Element *E = to_add_singleton.front(); E; E = E->next()) { - Node *al = get_node("/root/" + E->get()); - ERR_CONTINUE(!al); - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_named_global_constant(E->get(), al); + if (info.node) { + memdelete(info.node); + info.node = NULL; } } - // Add new nodes to the tree + // Load new/changed autoloads List<Node *> nodes_to_add; - for (List<AutoLoadInfo>::Element *E = to_add.front(); E; E = E->next()) { - AutoLoadInfo &info = E->get(); + for (List<AutoLoadInfo *>::Element *E = to_add.front(); E; E = E->next()) { + AutoLoadInfo *info = E->get(); - RES res = ResourceLoader::load(info.path); - ERR_EXPLAIN("Can't autoload: " + info.path); - ERR_CONTINUE(res.is_null()); - Node *n = NULL; - if (res->is_class("PackedScene")) { - Ref<PackedScene> ps = res; - n = ps->instance(); - } else if (res->is_class("Script")) { - Ref<Script> s = res; - StringName ibt = s->get_instance_base_type(); - bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_EXPLAIN("Script does not inherit a Node: " + info.path); - ERR_CONTINUE(!valid_type); - - Object *obj = ClassDB::instance(ibt); - - ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); - ERR_CONTINUE(obj == NULL); - - n = Object::cast_to<Node>(obj); - n->set_script(s.get_ref_ptr()); - } + info->node = _create_autoload(info->path); - ERR_EXPLAIN("Path in autoload not a node or script: " + info.path); - ERR_CONTINUE(!n); - n->set_name(info.name); + ERR_CONTINUE(!info->node); + info->node->set_name(info->name); - //defer so references are all valid on _ready() - nodes_to_add.push_back(n); + Ref<Script> scr = info->node->get_script(); + info->in_editor = scr.is_valid() && scr->is_tool(); - if (info.is_singleton) { + if (info->in_editor) { + //defer so references are all valid on _ready() + nodes_to_add.push_back(info->node); + } + + if (info->is_singleton) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { - ScriptServer::get_language(i)->add_named_global_constant(info.name, n); + ScriptServer::get_language(i)->add_named_global_constant(info->name, info->node); } } + + if (!info->in_editor && !info->is_singleton) { + // No reason to keep this node + memdelete(info->node); + info->node = NULL; + } } for (List<Node *>::Element *E = nodes_to_add.front(); E; E = E->next()) { @@ -728,6 +742,24 @@ EditorAutoloadSettings::EditorAutoloadSettings() { info.name = name; info.path = path; info.order = ProjectSettings::get_singleton()->get_order(pi.name); + info.node = _create_autoload(path); + + if (info.node) { + Ref<Script> scr = info.node->get_script(); + info.in_editor = scr.is_valid() && scr->is_tool(); + info.node->set_name(info.name); + } + + if (info.is_singleton) { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + ScriptServer::get_language(i)->add_named_global_constant(info.name, info.node); + } + } + + if (!info.is_singleton && !info.in_editor) { + memdelete(info.node); + info.node = NULL; + } autoload_cache.push_back(info); } @@ -796,3 +828,12 @@ EditorAutoloadSettings::EditorAutoloadSettings() { add_child(tree, true); } + +EditorAutoloadSettings::~EditorAutoloadSettings() { + for (List<AutoLoadInfo>::Element *E = autoload_cache.front(); E; E = E->next()) { + AutoLoadInfo &info = E->get(); + if (info.node && !info.in_editor) { + memdelete(info.node); + } + } +} diff --git a/editor/editor_autoload_settings.h b/editor/editor_autoload_settings.h index 1797c10e61..0b75faa009 100644 --- a/editor/editor_autoload_settings.h +++ b/editor/editor_autoload_settings.h @@ -52,11 +52,19 @@ class EditorAutoloadSettings : public VBoxContainer { String name; String path; bool is_singleton; + bool in_editor; int order; + Node *node; bool operator==(const AutoLoadInfo &p_info) { return order == p_info.order; } + + AutoLoadInfo() { + is_singleton = false; + in_editor = false; + node = NULL; + } }; List<AutoLoadInfo> autoload_cache; @@ -78,6 +86,7 @@ class EditorAutoloadSettings : public VBoxContainer { void _autoload_activated(); void _autoload_open(const String &fpath); void _autoload_file_callback(const String &p_path); + Node *_create_autoload(const String &p_path); Variant get_drag_data_fw(const Point2 &p_point, Control *p_control); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_control) const; @@ -93,6 +102,7 @@ public: void autoload_remove(const String &p_name); EditorAutoloadSettings(); + ~EditorAutoloadSettings(); }; #endif diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 38e74c126e..f94b7cd6ee 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -37,7 +37,8 @@ #include "scene/resources/packed_scene.h" // TODO: -// arrays +// arrays and dictionary +// replace property editor in sectionedpropertyeditor Size2 EditorProperty::get_minimum_size() const { @@ -51,6 +52,9 @@ Size2 EditorProperty::get_minimum_size() const { continue; if (!c->is_visible()) continue; + if (c == bottom_editor) + continue; + Size2 minsize = c->get_combined_minimum_size(); ms.width = MAX(ms.width, minsize.width); ms.height = MAX(ms.height, minsize.height); @@ -66,10 +70,14 @@ Size2 EditorProperty::get_minimum_size() const { ms.width += check->get_width() + get_constant("hseparator", "Tree"); } - if (label_layout == LABEL_LAYOUT_TOP) { + if (bottom_editor != NULL) { Ref<Font> font = get_font("font", "Tree"); ms.height += font->get_height(); ms.height += get_constant("vseparation", "Tree"); + Size2 bems = bottom_editor->get_combined_minimum_size(); + bems.width += get_constant("item_margin", "Tree"); + ms.height += bems.height; + ms.width = MAX(ms.width, bems.width); } return ms; @@ -81,9 +89,12 @@ void EditorProperty::_notification(int p_what) { Size2 size = get_size(); Rect2 rect; + Rect2 bottom_rect; - if (label_layout == LABEL_LAYOUT_LEFT) { + { int child_room = size.width / 2; + Ref<Font> font = get_font("font", "Tree"); + int height = font->get_height(); //compute room needed for (int i = 0; i < get_child_count(); i++) { @@ -93,22 +104,23 @@ void EditorProperty::_notification(int p_what) { continue; if (c->is_set_as_toplevel()) continue; + if (c == bottom_editor) + continue; Size2 minsize = c->get_combined_minimum_size(); child_room = MAX(child_room, minsize.width); + height = MAX(height, minsize.height); } text_size = MAX(0, size.width - child_room + 4 * EDSCALE); - rect = Rect2(text_size, 0, size.width - text_size, size.height); - } else { - Ref<Font> font = get_font("font", "Tree"); + rect = Rect2(text_size, 0, size.width - text_size, height); - text_size = size.width; - rect.position.x = 0; - rect.position.y = font->get_height() + get_constant("vseparation", "Tree"); - rect.size = get_size(); - rect.size.height -= rect.position.y; + if (bottom_editor) { + + int m = get_constant("item_margin", "Tree"); + bottom_rect = Rect2(m, rect.size.height + get_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height); + } } if (keying) { @@ -131,10 +143,16 @@ void EditorProperty::_notification(int p_what) { continue; if (c->is_set_as_toplevel()) continue; + if (c == bottom_editor) + continue; fit_child_in_rect(c, rect); } + if (bottom_editor) { + fit_child_in_rect(bottom_editor, bottom_rect); + } + update(); //need to redraw text } @@ -142,8 +160,8 @@ void EditorProperty::_notification(int p_what) { Ref<Font> font = get_font("font", "Tree"); Size2 size = get_size(); - if (label_layout == LABEL_LAYOUT_TOP) { - size.height = font->get_height(); + if (bottom_editor) { + size.height = bottom_editor->get_margin(MARGIN_TOP); } else if (label_reference) { size.height = label_reference->get_size().height; } @@ -502,6 +520,8 @@ bool EditorProperty::is_draw_red() const { void EditorProperty::_focusable_focused(int p_index) { + if (!selectable) + return; bool already_selected = selected; selected = true; selected_focusable = p_index; @@ -578,7 +598,7 @@ void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) { if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { - if (!selected) { + if (!selected && selectable) { selected = true; emit_signal("selected", property, -1); update(); @@ -626,7 +646,10 @@ void EditorProperty::set_label_reference(Control *p_control) { label_reference = p_control; } +void EditorProperty::set_bottom_editor(Control *p_control) { + bottom_editor = p_control; +} Variant EditorProperty::get_drag_data(const Point2 &p_point) { if (property == StringName()) @@ -644,10 +667,33 @@ Variant EditorProperty::get_drag_data(const Point2 &p_point) { return dp; } -void EditorProperty::set_label_layout(LabelLayout p_layout) { - label_layout = p_layout; - queue_sort(); - update(); +void EditorProperty::set_use_folding(bool p_use_folding) { + + use_folding = p_use_folding; +} + +bool EditorProperty::is_using_folding() const { + + return use_folding; +} + +void EditorProperty::expand_all_folding() { +} + +void EditorProperty::collapse_all_folding() { +} + +void EditorProperty::set_selectable(bool p_selectable) { + selectable = p_selectable; +} + +bool EditorProperty::is_selectable() const { + return selectable; +} + +void EditorProperty::set_object_and_property(Object *p_object, const StringName &p_property) { + object = p_object; + property = p_property; } void EditorProperty::_bind_methods() { @@ -685,6 +731,7 @@ void EditorProperty::_bind_methods() { ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::POOL_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value"))); ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"))); + ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::STRING, "bool"))); ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource"))); ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::INT, "id"))); @@ -697,6 +744,7 @@ void EditorProperty::_bind_methods() { EditorProperty::EditorProperty() { + selectable = true; text_size = 0; read_only = false; checkable = false; @@ -707,11 +755,12 @@ EditorProperty::EditorProperty() { revert_hover = false; check_hover = false; can_revert = false; + use_folding = false; property_usage = 0; selected = false; selected_focusable = -1; label_reference = NULL; - label_layout = LABEL_LAYOUT_LEFT; + bottom_editor = NULL; } //////////////////////////////////////////////// //////////////////////////////////////////////// @@ -755,6 +804,14 @@ void EditorInspectorPlugin::parse_begin(Object *p_object) { get_script_instance()->call("parse_begin", p_object); } } + +void EditorInspectorPlugin::parse_category(Object *p_object, const String &p_parse_category) { + + if (get_script_instance()) { + get_script_instance()->call("parse_category", p_object, p_parse_category); + } +} + bool EditorInspectorPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { if (get_script_instance()) { @@ -789,6 +846,10 @@ void EditorInspectorPlugin::_bind_methods() { BIND_VMETHOD(vm); vm.name = "parse_begin"; BIND_VMETHOD(vm); + vm.name = "parse_category"; + vm.arguments.push_back(PropertyInfo(Variant::STRING, "category")); + BIND_VMETHOD(vm); + vm.arguments.pop_back(); vm.name = "parse_property"; vm.return_val.type = Variant::BOOL; vm.arguments.push_back(PropertyInfo(Variant::INT, "type")); @@ -1096,6 +1157,55 @@ String EditorInspector::get_selected_path() const { return property_selected; } +void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<EditorInspectorPlugin> ped) { + + for (List<EditorInspectorPlugin::AddedEditor>::Element *F = ped->added_editors.front(); F; F = F->next()) { + + EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor); + current_vbox->add_child(F->get().property_editor); + + if (ep) { + + ep->object = object; + ep->connect("property_changed", this, "_property_changed"); + ep->connect("property_keyed", this, "_property_keyed"); + ep->connect("property_keyed_with_value", this, "_property_keyed_with_value"); + ep->connect("property_checked", this, "_property_checked"); + ep->connect("selected", this, "_property_selected"); + ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); + ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); + ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); + + if (F->get().properties.size()) { + + if (F->get().properties.size() == 1) { + //since it's one, associate: + ep->property = F->get().properties[0]; + ep->property_usage = 0; + } + + if (F->get().label != String()) { + ep->set_label(F->get().label); + } + + for (int i = 0; i < F->get().properties.size(); i++) { + String prop = F->get().properties[i]; + + if (!editor_property_map.has(prop)) { + editor_property_map[prop] = List<EditorProperty *>(); + } + editor_property_map[prop].push_back(ep); + } + } + + ep->set_read_only(read_only); + ep->update_property(); + ep->update_reload_status(); + } + } + ped->added_editors.clear(); +} + void EditorInspector::update_tree() { //to update properly if all is refreshed @@ -1139,6 +1249,12 @@ void EditorInspector::update_tree() { Color sscolor = get_color("prop_subsection", "Editor"); + for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { + Ref<EditorInspectorPlugin> ped = E->get(); + ped->parse_begin(object); + _parse_added_editors(main_vbox, ped); + } + for (List<PropertyInfo>::Element *I = plist.front(); I; I = I->next()) { PropertyInfo &p = I->get(); @@ -1201,6 +1317,13 @@ void EditorInspector::update_tree() { category->set_tooltip(TTR("Class:") + " " + p.name + (class_descr_cache[type] == "" ? "" : "\n\n" + class_descr_cache[type])); } + + for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { + Ref<EditorInspectorPlugin> ped = E->get(); + ped->parse_category(object, p.name); + _parse_added_editors(main_vbox, ped); + } + continue; } else if (!(p.usage & PROPERTY_USAGE_EDITOR)) @@ -1339,7 +1462,10 @@ void EditorInspector::update_tree() { for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { Ref<EditorInspectorPlugin> ped = E->get(); ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage); - for (List<EditorInspectorPlugin::AddedEditor>::Element *F = ped->added_editors.front(); F; F = F->next()) { + List<EditorInspectorPlugin::AddedEditor> editors = ped->added_editors; //make a copy, since plugins may be used again in a sub-inspector + ped->added_editors.clear(); + + for (List<EditorInspectorPlugin::AddedEditor>::Element *F = editors.front(); F; F = F->next()) { EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor); current_vbox->add_child(F->get().property_editor); @@ -1349,6 +1475,7 @@ void EditorInspector::update_tree() { ep->object = object; ep->connect("property_changed", this, "_property_changed"); ep->connect("property_keyed", this, "_property_keyed"); + ep->connect("property_keyed_with_value", this, "_property_keyed_with_value"); ep->connect("property_checked", this, "_property_checked"); ep->connect("selected", this, "_property_selected"); ep->connect("multiple_properties_changed", this, "_multiple_properties_changed"); @@ -1360,6 +1487,7 @@ void EditorInspector::update_tree() { ep->set_tooltip(TTR("Property: ") + p.name); } ep->set_draw_red(draw_red); + ep->set_use_folding(use_folding); ep->set_checkable(checkable); ep->set_checked(checked); ep->set_keying(keying); @@ -1398,10 +1526,15 @@ void EditorInspector::update_tree() { } } } - ped->added_editors.clear(); } } + for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) { + Ref<EditorInspectorPlugin> ped = E->get(); + ped->parse_end(); + _parse_added_editors(main_vbox, ped); + } + //see if this property exists and should be kept } void EditorInspector::update_property(const String &p_prop) { @@ -1416,14 +1549,14 @@ void EditorInspector::update_property(const String &p_prop) { void EditorInspector::_clear() { - editor_property_map.clear(); - sections.clear(); - pending.clear(); - property_selected = StringName(); - property_focusable = -1; while (main_vbox->get_child_count()) { memdelete(main_vbox->get_child(0)); } + property_selected = StringName(); + property_focusable = -1; + editor_property_map.clear(); + sections.clear(); + pending.clear(); } void EditorInspector::refresh() { @@ -1433,17 +1566,21 @@ void EditorInspector::refresh() { refresh_countdown = EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval"); } -void EditorInspector::edit(Object *p_object) { - if (object != p_object) { - _clear(); - } +Object *EditorInspector::get_edited_object() { + return object; +} +void EditorInspector::edit(Object *p_object) { + if (object == p_object) + return; if (object) { + _clear(); object->remove_change_receptor(this); } object = p_object; + if (object) { object->add_change_receptor(this); update_tree(); @@ -1518,12 +1655,23 @@ void EditorInspector::collapse_all_folding() { for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) { E->get()->fold(); } + + for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) { + for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) { + E->get()->collapse_all_folding(); + } + } } void EditorInspector::expand_all_folding() { for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) { E->get()->unfold(); } + for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) { + for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) { + E->get()->expand_all_folding(); + } + } } void EditorInspector::set_scroll_offset(int p_offset) { @@ -1653,6 +1801,14 @@ void EditorInspector::_property_keyed(const String &p_path) { emit_signal("property_keyed", p_path, object->get(p_path), false); //second param is deprecated } +void EditorInspector::_property_keyed_with_value(const String &p_path, const Variant &p_value) { + + if (!object) + return; + + emit_signal("property_keyed", p_path, p_value, false); //second param is deprecated +} + void EditorInspector::_property_checked(const String &p_path, bool p_checked) { if (!object) @@ -1791,6 +1947,7 @@ void EditorInspector::_bind_methods() { ClassDB::bind_method("_node_removed", &EditorInspector::_node_removed); ClassDB::bind_method("_filter_changed", &EditorInspector::_filter_changed); ClassDB::bind_method("_property_keyed", &EditorInspector::_property_keyed); + ClassDB::bind_method("_property_keyed_with_value", &EditorInspector::_property_keyed_with_value); ClassDB::bind_method("_property_checked", &EditorInspector::_property_checked); ClassDB::bind_method("_property_selected", &EditorInspector::_property_selected); ClassDB::bind_method("_resource_selected", &EditorInspector::_resource_selected); @@ -1807,9 +1964,8 @@ EditorInspector::EditorInspector() { main_vbox = memnew(VBoxContainer); main_vbox->set_h_size_flags(SIZE_EXPAND_FILL); add_child(main_vbox); - main_vbox->set_name("pipirulo"); - set_h_scroll(false); - set_v_scroll(true); + set_enable_h_scroll(false); + set_enable_v_scroll(true); show_categories = false; hide_script = true; diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 410c76dbb6..a6b183799f 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -31,18 +31,15 @@ #ifndef EDITOR_INSPECTOR_H #define EDITOR_INSPECTOR_H -#include "editor_data.h" +#include "scene/gui/box_container.h" +#include "scene/gui/line_edit.h" #include "scene/gui/scroll_container.h" +class UndoRedo; + class EditorProperty : public Container { GDCLASS(EditorProperty, Container) -public: - enum LabelLayout { - LABEL_LAYOUT_LEFT, - LABEL_LAYOUT_TOP, - }; - private: String label; int text_size; @@ -50,8 +47,6 @@ private: Object *object; StringName property; - LabelLayout label_layout; - int property_usage; bool read_only; @@ -69,17 +64,21 @@ private: bool can_revert; + bool use_folding; + bool _might_be_in_instance(); bool _is_property_different(const Variant &p_current, const Variant &p_orig, int p_usage); bool _is_instanced_node_with_original_property_different(); bool _get_instanced_node_original_property(const StringName &p_prop, Variant &value); void _focusable_focused(int p_index); + bool selectable; bool selected; int selected_focusable; Vector<Control *> focusables; Control *label_reference; + Control *bottom_editor; protected: void _notification(int p_what); @@ -122,10 +121,20 @@ public: bool is_selected() const; void set_label_reference(Control *p_control); + void set_bottom_editor(Control *p_editor); + + void set_use_folding(bool p_use_folding); + bool is_using_folding() const; + + virtual void expand_all_folding(); + virtual void collapse_all_folding(); virtual Variant get_drag_data(const Point2 &p_point); - void set_label_layout(LabelLayout p_layout); + void set_selectable(bool p_selectable); + bool is_selectable() const; + + void set_object_and_property(Object *p_object, const StringName &p_property); EditorProperty(); }; @@ -151,6 +160,7 @@ public: virtual bool can_handle(Object *p_object); virtual void parse_begin(Object *p_object); + virtual void parse_category(Object *p_object, const String &p_parse_category); virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); virtual void parse_end(); }; @@ -249,6 +259,8 @@ class EditorInspector : public ScrollContainer { void _property_changed(const String &p_path, const Variant &p_value); void _multiple_properties_changed(Vector<String> p_paths, Array p_values); void _property_keyed(const String &p_path); + void _property_keyed_with_value(const String &p_path, const Variant &p_value); + void _property_checked(const String &p_path, bool p_checked); void _resource_selected(const String &p_path, RES p_resource); @@ -261,6 +273,7 @@ class EditorInspector : public ScrollContainer { void _edit_request_change(Object *p_changed, const String &p_prop); void _filter_changed(const String &p_text); + void _parse_added_editors(VBoxContainer *current_vbox, Ref<EditorInspectorPlugin> ped); protected: static void _bind_methods(); @@ -281,6 +294,7 @@ public: void refresh(); void edit(Object *p_object); + Object *get_edited_object(); void set_keying(bool p_active); void set_read_only(bool p_read_only); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 49f70e3215..dd3b6c2c4c 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -295,7 +295,6 @@ void EditorNode::_notification(int p_what) { get_tree()->get_root()->set_as_audio_listener_2d(false); get_tree()->set_auto_accept_quit(false); get_tree()->connect("files_dropped", this, "_dropped_files"); - property_editable_warning->set_icon(gui_base->get_icon("NodeWarning", "EditorIcons")); } if (p_what == NOTIFICATION_EXIT_TREE) { @@ -324,7 +323,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/scene_tabs/always_show_close_button", false)) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY)); + scene_tabs->set_tab_close_display_policy((bool(EDITOR_GET("interface/scene_tabs/always_show_close_button")) ? Tabs::CLOSE_BUTTON_SHOW_ALWAYS : Tabs::CLOSE_BUTTON_SHOW_ACTIVE_ONLY)); Ref<Theme> theme = create_editor_theme(theme_base->get_theme()); theme_base->set_theme(theme); @@ -343,8 +342,8 @@ void EditorNode::_notification(int p_what) { settings_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles")); help_menu->add_style_override("hover", gui_base->get_stylebox("MenuHover", "EditorStyles")); - if (bool(EDITOR_DEF("interface/scene_tabs/resize_if_many_tabs", true))) { - scene_tabs->set_min_width(int(EDITOR_DEF("interface/scene_tabs/minimum_width", 50)) * EDSCALE); + if (EDITOR_GET("interface/scene_tabs/resize_if_many_tabs")) { + scene_tabs->set_min_width(int(EDITOR_GET("interface/scene_tabs/minimum_width")) * EDSCALE); } else { scene_tabs->set_min_width(0); } @@ -382,16 +381,6 @@ void EditorNode::_notification(int p_what) { distraction_free->set_icon(gui_base->get_icon("DistractionFree", "EditorIcons")); scene_tab_add->set_icon(gui_base->get_icon("Add", "EditorIcons")); - resource_new_button->set_icon(gui_base->get_icon("New", "EditorIcons")); - resource_load_button->set_icon(gui_base->get_icon("Load", "EditorIcons")); - resource_save_button->set_icon(gui_base->get_icon("Save", "EditorIcons")); - - property_back->set_icon(gui_base->get_icon("Back", "EditorIcons")); - property_forward->set_icon(gui_base->get_icon("Forward", "EditorIcons")); - editor_history_menu->set_icon(gui_base->get_icon("History", "EditorIcons")); - - search_button->set_icon(gui_base->get_icon("Search", "EditorIcons")); - object_menu->set_icon(gui_base->get_icon("Tools", "EditorIcons")); // clear_button->set_icon(gui_base->get_icon("Close", "EditorIcons")); don't have access to that node. needs to become a class property update_menu->set_icon(gui_base->get_icon("Collapse", "EditorIcons")); dock_tab_move_left->set_icon(theme->get_icon("Back", "EditorIcons")); @@ -549,8 +538,8 @@ void EditorNode::_vp_resized() { void EditorNode::_node_renamed() { - if (inspector) - inspector->update_tree(); + if (get_inspector()) + get_inspector()->update_tree(); } void EditorNode::_editor_select_next() { @@ -582,38 +571,16 @@ Error EditorNode::load_resource(const String &p_scene) { RES res = ResourceLoader::load(p_scene); ERR_FAIL_COND_V(!res.is_valid(), ERR_CANT_OPEN); - edit_resource(res); + inspector_dock->edit_resource(res); return OK; } -void EditorNode::edit_resource(const Ref<Resource> &p_resource) { - - _resource_selected(p_resource, ""); -} - void EditorNode::edit_node(Node *p_node) { push_item(p_node); } -void EditorNode::open_resource(const String &p_type) { - - file->set_mode(EditorFileDialog::MODE_OPEN_FILE); - - List<String> extensions; - ResourceLoader::get_recognized_extensions_for_type(p_type, &extensions); - - file->clear_filters(); - for (int i = 0; i < extensions.size(); i++) { - - file->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); - } - - file->popup_centered_ratio(); - current_option = RESOURCE_LOAD; -} - void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) { editor_data.apply_changes_in_editors(); @@ -1145,20 +1112,6 @@ void EditorNode::_mark_unsaved_scenes() { void EditorNode::_dialog_action(String p_file) { switch (current_option) { - - case RESOURCE_LOAD: { - - RES res = ResourceLoader::load(p_file); - if (res.is_null()) { - - current_option = -1; - accept->get_ok()->set_text("Ugh"); - accept->set_text(TTR("Failed to load resource.")); - return; - }; - - push_item(res.operator->()); - } break; case FILE_NEW_INHERITED_SCENE: { load_scene(p_file, false, true); @@ -1352,7 +1305,7 @@ void EditorNode::_dialog_action(String p_file) { void EditorNode::push_item(Object *p_object, const String &p_property) { if (!p_object) { - inspector->edit(NULL); + get_inspector()->edit(NULL); node_dock->set_node(NULL); scene_tree_dock->set_selected(NULL); return; @@ -1370,89 +1323,6 @@ void EditorNode::push_item(Object *p_object, const String &p_property) { _edit_current(); } -void EditorNode::_select_history(int p_idx) { - - //push it to the top, it is not correct, but it's more useful - ObjectID id = editor_history.get_history_obj(p_idx); - Object *obj = ObjectDB::get_instance(id); - if (!obj) - return; - push_item(obj); -} - -void EditorNode::_prepare_history() { - - int history_to = MAX(0, editor_history.get_history_len() - 25); - - editor_history_menu->get_popup()->clear(); - - Ref<Texture> base_icon = gui_base->get_icon("Object", "EditorIcons"); - Set<ObjectID> already; - for (int i = editor_history.get_history_len() - 1; i >= history_to; i--) { - - ObjectID id = editor_history.get_history_obj(i); - Object *obj = ObjectDB::get_instance(id); - if (!obj || already.has(id)) { - if (history_to > 0) { - history_to--; - } - continue; - } - - already.insert(id); - - Ref<Texture> icon = gui_base->get_icon("Object", "EditorIcons"); - if (gui_base->has_icon(obj->get_class(), "EditorIcons")) - icon = gui_base->get_icon(obj->get_class(), "EditorIcons"); - else - icon = base_icon; - - String text; - if (Object::cast_to<Resource>(obj)) { - Resource *r = Object::cast_to<Resource>(obj); - if (r->get_path().is_resource_file()) - text = r->get_path().get_file(); - else if (r->get_name() != String()) { - text = r->get_name(); - } else { - text = r->get_class(); - } - } 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(); - } - - if (i == editor_history.get_history_pos()) { - text = "[" + text + "]"; - } - editor_history_menu->get_popup()->add_icon_item(icon, text, i); - } -} - -void EditorNode::_property_editor_forward() { - - if (editor_history.next()) - _edit_current(); -} -void EditorNode::_property_editor_back() { - - if (editor_history.previous() || editor_history.get_path_size() == 1) - _edit_current(); -} - -void EditorNode::_menu_collapseall() { - - inspector->collapse_all_folding(); -} - -void EditorNode::_menu_expandall() { - - inspector->expand_all_folding(); -} - void EditorNode::_save_default_environment() { Ref<Environment> fallback = get_tree()->get_root()->get_world()->get_fallback_environment(); @@ -1494,52 +1364,38 @@ static bool overrides_external_editor(Object *p_object) { return script->get_language()->overrides_external_editor(); } -void EditorNode::_property_editable_warning_pressed() { - - property_editable_warning_dialog->popup_centered_minsize(); -} - void EditorNode::_edit_current() { uint32_t current = editor_history.get_current(); Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; - property_back->set_disabled(editor_history.is_at_beginning()); - property_forward->set_disabled(editor_history.is_at_end()); - this->current = current_obj; - editor_path->update_path(); - - String editable_warning; //none by default - property_editable_warning->hide(); //hide by default if (!current_obj) { scene_tree_dock->set_selected(NULL); - inspector->edit(NULL); + get_inspector()->edit(NULL); node_dock->set_node(NULL); - object_menu->set_disabled(true); + inspector_dock->update(NULL); _display_top_editors(false); return; } - 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); + + String editable_warning; //none by default if (is_resource) { Resource *current_res = Object::cast_to<Resource>(current_obj); ERR_FAIL_COND(!current_res); scene_tree_dock->set_selected(NULL); - inspector->edit(current_res); + get_inspector()->edit(current_res); node_dock->set_node(NULL); - object_menu->set_disabled(false); EditorNode::get_singleton()->get_import_dock()->set_edit_path(current_res->get_path()); int subr_idx = current_res->get_path().find("::"); @@ -1562,7 +1418,7 @@ void EditorNode::_edit_current() { Node *current_node = Object::cast_to<Node>(current_obj); ERR_FAIL_COND(!current_node); - inspector->edit(current_node); + get_inspector()->edit(current_node); if (current_node->is_inside_tree()) { node_dock->set_node(current_node); scene_tree_dock->set_selected(current_node); @@ -1570,7 +1426,6 @@ void EditorNode::_edit_current() { node_dock->set_node(NULL); scene_tree_dock->set_selected(NULL); } - object_menu->get_popup()->clear(); if (get_edited_scene() && get_edited_scene()->get_filename() != String()) { String source_scene = get_edited_scene()->get_filename(); @@ -1586,17 +1441,14 @@ void EditorNode::_edit_current() { capitalize = false; } - inspector->edit(current_obj); + get_inspector()->edit(current_obj); node_dock->set_node(NULL); } - if (editable_warning != String()) { - property_editable_warning->show(); //hide by default - property_editable_warning_dialog->set_text(editable_warning); - } + inspector_dock->set_warning(editable_warning); - if (inspector->is_capitalize_paths_enabled() != capitalize) { - inspector->set_enable_capitalize_paths(capitalize); + if (get_inspector()->is_capitalize_paths_enabled() != capitalize) { + get_inspector()->set_enable_capitalize_paths(capitalize); } /* Take care of PLUGIN EDITOR */ @@ -1654,75 +1506,8 @@ void EditorNode::_edit_current() { _hide_top_editors(); } - object_menu->set_disabled(false); - - PopupMenu *p = object_menu->get_popup(); - - p->clear(); - p->add_shortcut(ED_SHORTCUT("property_editor/expand_all", TTR("Expand all properties")), EXPAND_ALL); - p->add_shortcut(ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse all properties")), COLLAPSE_ALL); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS); - p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Paste Resource")), RESOURCE_PASTE); - if (is_resource) { - p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY); - p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_UNREF); - } - - if (is_resource || is_node) { - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("property_editor/make_subresources_unique", TTR("Make Sub-Resources Unique")), OBJECT_UNIQUE_RESOURCES); - p->add_separator(); - p->add_icon_shortcut(gui_base->get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP); - } - - List<MethodInfo> methods; - current_obj->get_method_list(&methods); - - if (!methods.empty()) { - - bool found = false; - List<MethodInfo>::Element *I = methods.front(); - int i = 0; - while (I) { - - if (I->get().flags & METHOD_FLAG_EDITOR) { - if (!found) { - p->add_separator(); - found = true; - } - p->add_item(I->get().name.capitalize(), OBJECT_METHOD_BASE + i); - } - i++; - I = I->next(); - } - } - - update_keying(); -} - -void EditorNode::_resource_created() { - - Object *c = create_dialog->instance_selected(); - - ERR_FAIL_COND(!c); - Resource *r = Object::cast_to<Resource>(c); - ERR_FAIL_COND(!r); - - REF res(r); - - push_item(c); -} - -void EditorNode::_resource_selected(const RES &p_res, const String &p_property) { - - if (p_res.is_null()) - return; - - RES r = p_res; - push_item(r.operator->(), p_property); + inspector_dock->update(current_obj); + inspector_dock->update_keying(); } void EditorNode::_run(bool p_current, const String &p_custom) { @@ -1796,7 +1581,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { } } - if (bool(EDITOR_DEF("run/auto_save/save_before_running", true))) { + if (bool(EDITOR_GET("run/auto_save/save_before_running"))) { if (unsaved_cache) { @@ -1823,11 +1608,11 @@ void EditorNode::_run(bool p_current, const String &p_custom) { if (!call_build()) return; - if (bool(EDITOR_DEF("run/output/always_clear_output_on_play", true))) { + if (bool(EDITOR_GET("run/output/always_clear_output_on_play"))) { log->clear(); } - if (bool(EDITOR_DEF("run/output/always_open_output_on_play", true))) { + if (bool(EDITOR_GET("run/output/always_open_output_on_play"))) { make_bottom_panel_item_visible(log); } @@ -2163,136 +1948,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { scene_tabs->set_current_tab(cur_idx); } break; - case RESOURCE_NEW: { - - create_dialog->popup_create(true); - } break; - case RESOURCE_LOAD: { - - open_resource(); - } break; - case RESOURCE_SAVE: { - - uint32_t current = editor_history.get_current(); - Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; - - ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) - - RES current_res = RES(Object::cast_to<Resource>(current_obj)); - - save_resource(current_res); - - } break; - case RESOURCE_SAVE_AS: { - - uint32_t current = editor_history.get_current(); - Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; - - ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) - - RES current_res = RES(Object::cast_to<Resource>(current_obj)); - - save_resource_as(current_res); - - } break; - case RESOURCE_UNREF: { - - uint32_t current = editor_history.get_current(); - Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; - - ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) - - RES current_res = RES(Object::cast_to<Resource>(current_obj)); - current_res->set_path(""); - _edit_current(); - } break; - case RESOURCE_COPY: { - - uint32_t current = editor_history.get_current(); - Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; - - ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) - - RES current_res = RES(Object::cast_to<Resource>(current_obj)); - - EditorSettings::get_singleton()->set_resource_clipboard(current_res); - - } break; - case RESOURCE_PASTE: { - - RES r = EditorSettings::get_singleton()->get_resource_clipboard(); - if (r.is_valid()) { - push_item(EditorSettings::get_singleton()->get_resource_clipboard().ptr(), String()); - } - - } break; - case OBJECT_REQUEST_HELP: { - - if (current) { - _editor_select(EDITOR_SCRIPT); - emit_signal("request_help", current->get_class()); - } - - } break; - case OBJECT_COPY_PARAMS: { - - editor_data.apply_changes_in_editors(); - if (current) - editor_data.copy_object_params(current); - } break; - case OBJECT_PASTE_PARAMS: { - - editor_data.apply_changes_in_editors(); - if (current) - editor_data.paste_object_params(current); - editor_data.get_undo_redo().clear_history(); - } break; - case OBJECT_UNIQUE_RESOURCES: { - - editor_data.apply_changes_in_editors(); - if (current) { - List<PropertyInfo> props; - current->get_property_list(&props); - Map<RES, RES> duplicates; - for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { - - if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) - continue; - - Variant v = current->get(E->get().name); - if (v.is_ref()) { - REF ref = v; - if (ref.is_valid()) { - - RES res = ref; - if (res.is_valid()) { - - if (!duplicates.has(res)) { - duplicates[res] = res->duplicate(); - } - res = duplicates[res]; - - current->set(E->get().name, res); - } - } - } - } - } - - editor_data.get_undo_redo().clear_history(); - - _set_editing_top_editors(NULL); - _set_editing_top_editors(current); - - } break; - case COLLAPSE_ALL: { - _menu_collapseall(); - - } break; - case EXPAND_ALL: { - _menu_expandall(); - - } break; case RUN_PLAY: { _menu_option_confirm(RUN_STOP, true); _run(false); @@ -2326,7 +1981,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { play_custom_scene_button->set_icon(gui_base->get_icon("PlayCustom", "EditorIcons")); stop_button->set_disabled(true); - if (bool(EDITOR_DEF("run/output/always_close_output_on_stop", true))) { + if (bool(EDITOR_GET("run/output/always_close_output_on_stop"))) { for (int i = 0; i < bottom_panel_items.size(); i++) { if (bottom_panel_items[i].control == log) { _bottom_panel_switch(false, i); @@ -2346,7 +2001,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; case RUN_PLAY_NATIVE: { - bool autosave = EDITOR_DEF("run/auto_save/save_before_running", true); + bool autosave = EDITOR_GET("run/auto_save/save_before_running"); if (autosave) { _menu_option_confirm(FILE_SAVE_ALL_SCENES, false); } @@ -2372,10 +2027,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { case RUN_PROJECT_MANAGER: { if (!p_confirmed) { - bool save_each = EDITOR_DEF("interface/editor/save_each_scene_on_quit", true); + bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit"); if (_next_unsaved_scene(!save_each) == -1) { - bool confirm = EDITOR_DEF("interface/editor/quit_confirmation", true); + bool confirm = EDITOR_GET("interface/editor/quit_confirmation"); if (confirm) { confirmation->get_ok()->set_text(p_option == FILE_QUIT ? TTR("Quit") : TTR("Yes")); @@ -2555,22 +2210,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; default: { - - if (p_option >= OBJECT_METHOD_BASE) { - - ERR_FAIL_COND(!current); - - int idx = p_option - OBJECT_METHOD_BASE; - - List<MethodInfo> methods; - current->get_method_list(&methods); - - ERR_FAIL_INDEX(idx, methods.size()); - String name = methods[idx].name; - - if (current) - current->call(name); - } else if (p_option >= IMPORT_PLUGIN_BASE) { + if (p_option >= IMPORT_PLUGIN_BASE) { } } } @@ -3244,42 +2884,14 @@ SceneTreeDock *EditorNode::get_scene_tree_dock() { return scene_tree_dock; } +InspectorDock *EditorNode::get_inspector_dock() { -void EditorNode::_instance_request(const Vector<String> &p_files) { - - request_instance_scenes(p_files); -} - -void EditorNode::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) { - - AnimationPlayerEditor::singleton->get_key_editor()->insert_value_key(p_keyed, p_value, p_advance); -} - -void EditorNode::_transform_keyed(Object *sp, const String &p_sub, const Transform &p_key) { - - Spatial *s = Object::cast_to<Spatial>(sp); - if (!s) - return; - AnimationPlayerEditor::singleton->get_key_editor()->insert_transform_key(s, p_sub, p_key); + return inspector_dock; } -void EditorNode::update_keying() { - - bool valid = false; - - if (AnimationPlayerEditor::singleton->get_key_editor()->has_keying()) { - - if (editor_history.get_path_size() >= 1) { - - Object *obj = ObjectDB::get_instance(editor_history.get_path_object(0)); - if (Object::cast_to<Node>(obj)) { - - valid = true; - } - } - } +void EditorNode::_instance_request(const Vector<String> &p_files) { - inspector->set_keying(valid); + request_instance_scenes(p_files); } void EditorNode::_close_messages() { @@ -4044,7 +3656,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String } void EditorNode::_load_open_scenes_from_config(Ref<ConfigFile> p_layout, const String &p_section) { - if (!bool(EDITOR_DEF("interface/scene_tabs/restore_scenes_on_load", false))) { + if (!bool(EDITOR_GET("interface/scene_tabs/restore_scenes_on_load"))) { return; } @@ -4138,7 +3750,7 @@ void EditorNode::_scene_tab_script_edited(int p_tab) { Ref<Script> script = editor_data.get_scene_root_script(p_tab); if (script.is_valid()) - edit_resource(script); + inspector_dock->edit_resource(script); } void EditorNode::_scene_tab_closed(int p_tab) { @@ -4166,7 +3778,7 @@ void EditorNode::_scene_tab_closed(int p_tab) { } void EditorNode::_scene_tab_hover(int p_tab) { - if (bool(EDITOR_DEF("interface/scene_tabs/show_thumbnail_on_hover", true)) == false) { + if (bool(EDITOR_GET("interface/scene_tabs/show_thumbnail_on_hover")) == false) { return; } int current_tab = scene_tabs->get_current_tab(); @@ -4236,30 +3848,6 @@ void EditorNode::_scene_tab_changed(int p_tab) { editor_data.get_undo_redo().commit_action(); } -void EditorNode::_toggle_search_bar(bool p_pressed) { - - inspector->set_use_filter(p_pressed); - - if (p_pressed) { - - search_bar->show(); - search_box->grab_focus(); - search_box->select_all(); - } else { - - search_bar->hide(); - } -} - -void EditorNode::_clear_search_box() { - - if (search_box->get_text() == "") - return; - - search_box->clear(); - inspector->update_tree(); -} - ToolButton *EditorNode::add_bottom_panel_item(String p_text, Control *p_item) { ToolButton *tb = memnew(ToolButton); @@ -4778,9 +4366,6 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("_tool_menu_option", &EditorNode::_tool_menu_option); ClassDB::bind_method("_menu_confirm_current", &EditorNode::_menu_confirm_current); ClassDB::bind_method("_dialog_action", &EditorNode::_dialog_action); - ClassDB::bind_method("_resource_selected", &EditorNode::_resource_selected, DEFVAL("")); - ClassDB::bind_method("_property_editor_forward", &EditorNode::_property_editor_forward); - ClassDB::bind_method("_property_editor_back", &EditorNode::_property_editor_back); ClassDB::bind_method("_editor_select", &EditorNode::_editor_select); ClassDB::bind_method("_node_renamed", &EditorNode::_node_renamed); ClassDB::bind_method("edit_node", &EditorNode::edit_node); @@ -4790,16 +4375,12 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("set_edited_scene", &EditorNode::set_edited_scene); ClassDB::bind_method("open_request", &EditorNode::open_request); ClassDB::bind_method("_instance_request", &EditorNode::_instance_request); - ClassDB::bind_method("update_keying", &EditorNode::update_keying); - ClassDB::bind_method("_property_keyed", &EditorNode::_property_keyed); - ClassDB::bind_method("_transform_keyed", &EditorNode::_transform_keyed); ClassDB::bind_method("_close_messages", &EditorNode::_close_messages); ClassDB::bind_method("_show_messages", &EditorNode::_show_messages); ClassDB::bind_method("_vp_resized", &EditorNode::_vp_resized); ClassDB::bind_method("_quick_opened", &EditorNode::_quick_opened); ClassDB::bind_method("_quick_run", &EditorNode::_quick_run); - ClassDB::bind_method("_resource_created", &EditorNode::_resource_created); ClassDB::bind_method("_open_recent_scene", &EditorNode::_open_recent_scene); ClassDB::bind_method("stop_child_process", &EditorNode::stop_child_process); @@ -4833,15 +4414,9 @@ void EditorNode::_bind_methods() { ClassDB::bind_method("_discard_changes", &EditorNode::_discard_changes); ClassDB::bind_method("_update_recent_scenes", &EditorNode::_update_recent_scenes); - ClassDB::bind_method("_prepare_history", &EditorNode::_prepare_history); - ClassDB::bind_method("_select_history", &EditorNode::_select_history); - - ClassDB::bind_method("_toggle_search_bar", &EditorNode::_toggle_search_bar); - ClassDB::bind_method("_clear_search_box", &EditorNode::_clear_search_box); ClassDB::bind_method("_clear_undo_history", &EditorNode::_clear_undo_history); ClassDB::bind_method("_dropped_files", &EditorNode::_dropped_files); ClassDB::bind_method("_toggle_distraction_free_mode", &EditorNode::_toggle_distraction_free_mode); - ClassDB::bind_method("_property_editable_warning_pressed", &EditorNode::_property_editable_warning_pressed); ClassDB::bind_method(D_METHOD("get_gui_base"), &EditorNode::get_gui_base); ClassDB::bind_method(D_METHOD("_bottom_panel_switch"), &EditorNode::_bottom_panel_switch); @@ -4855,7 +4430,6 @@ void EditorNode::_bind_methods() { ADD_SIGNAL(MethodInfo("play_pressed")); ADD_SIGNAL(MethodInfo("pause_pressed")); ADD_SIGNAL(MethodInfo("stop_pressed")); - ADD_SIGNAL(MethodInfo("request_help")); ADD_SIGNAL(MethodInfo("request_help_search")); ADD_SIGNAL(MethodInfo("request_help_index")); ADD_SIGNAL(MethodInfo("script_add_function_request", PropertyInfo(Variant::OBJECT, "obj"), PropertyInfo(Variant::STRING, "function"), PropertyInfo(Variant::POOL_STRING_ARRAY, "args"))); @@ -5042,6 +4616,22 @@ EditorNode::EditorNode() { ClassDB::set_class_enabled("CollisionShape2D", true); ClassDB::set_class_enabled("CollisionPolygon2D", true); + //defs here, use EDITOR_GET in logic + EDITOR_DEF("interface/scene_tabs/always_show_close_button", false); + EDITOR_DEF("interface/scene_tabs/resize_if_many_tabs", true); + EDITOR_DEF("interface/scene_tabs/minimum_width", 50); + EDITOR_DEF("run/output/always_clear_output_on_play", true); + EDITOR_DEF("run/output/always_open_output_on_play", true); + EDITOR_DEF("run/output/always_close_output_on_stop", true); + EDITOR_DEF("run/auto_save/save_before_running", true); + EDITOR_DEF("interface/editor/save_each_scene_on_quit", true); + EDITOR_DEF("interface/editor/quit_confirmation", true); + EDITOR_DEF("interface/scene_tabs/restore_scenes_on_load", false); + EDITOR_DEF("interface/scene_tabs/show_thumbnail_on_hover", true); + EDITOR_DEF("interface/inspector/capitalize_properties", true); + EDITOR_DEF("interface/inspector/open_resources_in_new_inspector", false); + EDITOR_DEF("run/auto_save/save_before_running", true); + theme_base = memnew(Control); add_child(theme_base); theme_base->set_anchors_and_margins_preset(Control::PRESET_WIDE); @@ -5565,129 +5155,11 @@ EditorNode::EditorNode() { dock_slot[DOCK_SLOT_RIGHT_UL]->set_tab_title(scene_tree_dock->get_index(), TTR("Scene")); dock_slot[DOCK_SLOT_LEFT_BR]->hide(); - VBoxContainer *prop_editor_base = memnew(VBoxContainer); - prop_editor_base->set_name("Inspector"); - dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(prop_editor_base); - dock_slot[DOCK_SLOT_RIGHT_BL]->set_tab_title(prop_editor_base->get_index(), TTR("Inspector")); - - HBoxContainer *prop_editor_hb = memnew(HBoxContainer); - - prop_editor_base->add_child(prop_editor_hb); - prop_editor_vb = prop_editor_base; - - resource_new_button = memnew(ToolButton); - resource_new_button->set_tooltip(TTR("Create a new resource in memory and edit it.")); - resource_new_button->set_icon(gui_base->get_icon("New", "EditorIcons")); - prop_editor_hb->add_child(resource_new_button); - resource_new_button->connect("pressed", this, "_menu_option", varray(RESOURCE_NEW)); - resource_new_button->set_focus_mode(Control::FOCUS_NONE); - - resource_load_button = memnew(ToolButton); - resource_load_button->set_tooltip(TTR("Load an existing resource from disk and edit it.")); - resource_load_button->set_icon(gui_base->get_icon("Load", "EditorIcons")); - prop_editor_hb->add_child(resource_load_button); - resource_load_button->connect("pressed", this, "_menu_option", varray(RESOURCE_LOAD)); - resource_load_button->set_focus_mode(Control::FOCUS_NONE); - - resource_save_button = memnew(MenuButton); - resource_save_button->set_tooltip(TTR("Save the currently edited resource.")); - resource_save_button->set_icon(gui_base->get_icon("Save", "EditorIcons")); - prop_editor_hb->add_child(resource_save_button); - resource_save_button->get_popup()->add_item(TTR("Save"), RESOURCE_SAVE); - resource_save_button->get_popup()->add_item(TTR("Save As..."), RESOURCE_SAVE_AS); - resource_save_button->get_popup()->connect("id_pressed", this, "_menu_option"); - resource_save_button->set_focus_mode(Control::FOCUS_NONE); - resource_save_button->set_disabled(true); - - prop_editor_hb->add_spacer(); - - property_back = memnew(ToolButton); - property_back->set_icon(gui_base->get_icon("Back", "EditorIcons")); - property_back->set_flat(true); - property_back->set_tooltip(TTR("Go to the previous edited object in history.")); - property_back->set_disabled(true); - - prop_editor_hb->add_child(property_back); - - property_forward = memnew(ToolButton); - property_forward->set_icon(gui_base->get_icon("Forward", "EditorIcons")); - property_forward->set_flat(true); - property_forward->set_tooltip(TTR("Go to the next edited object in history.")); - property_forward->set_disabled(true); - - prop_editor_hb->add_child(property_forward); - - editor_history_menu = memnew(MenuButton); - editor_history_menu->set_tooltip(TTR("History of recently edited objects.")); - editor_history_menu->set_icon(gui_base->get_icon("History", "EditorIcons")); - prop_editor_hb->add_child(editor_history_menu); - editor_history_menu->connect("about_to_show", this, "_prepare_history"); - editor_history_menu->get_popup()->connect("id_pressed", this, "_select_history"); - - prop_editor_hb = memnew(HBoxContainer); //again... - prop_editor_base->add_child(prop_editor_hb); - - editor_path = memnew(EditorPath(&editor_history)); - editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); - prop_editor_hb->add_child(editor_path); - - search_button = memnew(ToolButton); - search_button->set_toggle_mode(true); - search_button->set_pressed(false); - search_button->set_icon(gui_base->get_icon("Search", "EditorIcons")); - prop_editor_hb->add_child(search_button); - search_button->connect("toggled", this, "_toggle_search_bar"); - - object_menu = memnew(MenuButton); - object_menu->set_icon(gui_base->get_icon("Tools", "EditorIcons")); - prop_editor_hb->add_child(object_menu); - object_menu->set_tooltip(TTR("Object properties.")); - - create_dialog = memnew(CreateDialog); - gui_base->add_child(create_dialog); - create_dialog->set_base_type("Resource"); - create_dialog->connect("create", this, "_resource_created"); - - search_bar = memnew(HBoxContainer); - search_bar->set_h_size_flags(Control::SIZE_EXPAND_FILL); - prop_editor_base->add_child(search_bar); - search_bar->hide(); - - Label *l = memnew(Label(TTR("Search:") + " ")); - search_bar->add_child(l); - - search_box = memnew(LineEdit); - search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL); - search_bar->add_child(search_box); - - ToolButton *clear_button = memnew(ToolButton); - clear_button->set_icon(gui_base->get_icon("Close", "EditorIcons")); - search_bar->add_child(clear_button); - clear_button->connect("pressed", this, "_clear_search_box"); - - property_editable_warning = memnew(Button); - property_editable_warning->set_text(TTR("Changes may be lost!")); - prop_editor_base->add_child(property_editable_warning); - property_editable_warning_dialog = memnew(AcceptDialog); - gui_base->add_child(property_editable_warning_dialog); - property_editable_warning->hide(); - property_editable_warning->connect("pressed", this, "_property_editable_warning_pressed"); - - inspector = memnew(EditorInspector); - inspector->set_autoclear(true); - inspector->set_show_categories(true); - inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); - inspector->set_use_doc_hints(true); - inspector->set_hide_script(false); - inspector->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); - inspector->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false))); - - // inspector->hide_top_label(); - inspector->register_text_enter(search_box); + inspector_dock = memnew(InspectorDock(this, editor_data)); + dock_slot[DOCK_SLOT_RIGHT_BL]->add_child(inspector_dock); + dock_slot[DOCK_SLOT_RIGHT_BL]->set_tab_title(inspector_dock->get_index(), TTR("Inspector")); Button *property_editable_warning; - prop_editor_base->add_child(inspector); - inspector->set_undo_redo(&editor_data.get_undo_redo()); import_dock = memnew(ImportDock); dock_slot[DOCK_SLOT_RIGHT_UL]->add_child(import_dock); @@ -5813,18 +5285,12 @@ EditorNode::EditorNode() { gui_base->add_child(file_script); file_script->connect("file_selected", this, "_dialog_action"); - property_forward->connect("pressed", this, "_property_editor_forward"); - property_back->connect("pressed", this, "_property_editor_back"); - file_menu->get_popup()->connect("id_pressed", this, "_menu_option"); - object_menu->get_popup()->connect("id_pressed", this, "_menu_option"); settings_menu->get_popup()->connect("id_pressed", this, "_menu_option"); file->connect("file_selected", this, "_dialog_action"); file_templates->connect("file_selected", this, "_dialog_action"); - inspector->connect("resource_selected", this, "_resource_selected"); - inspector->connect("property_keyed", this, "_property_keyed"); //plugin stuff diff --git a/editor/editor_node.h b/editor/editor_node.h index 86b85663ab..bef5bc816c 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -40,7 +40,6 @@ #include "editor/editor_inspector.h" #include "editor/editor_log.h" #include "editor/editor_name_dialog.h" -#include "editor/editor_path.h" #include "editor/editor_plugin.h" #include "editor/editor_resource_preview.h" #include "editor/editor_run.h" @@ -53,6 +52,7 @@ #include "editor/filesystem_dock.h" #include "editor/groups_editor.h" #include "editor/import_dock.h" +#include "editor/inspector_dock.h" #include "editor/node_dock.h" #include "editor/pane_drag.h" #include "editor/progress_dialog.h" @@ -142,22 +142,10 @@ private: EDIT_REVERT, TOOLS_ORPHAN_RESOURCES, TOOLS_CUSTOM, - RESOURCE_NEW, - RESOURCE_LOAD, RESOURCE_SAVE, RESOURCE_SAVE_AS, - RESOURCE_UNREF, - RESOURCE_COPY, - RESOURCE_PASTE, - OBJECT_COPY_PARAMS, - OBJECT_PASTE_PARAMS, - OBJECT_UNIQUE_RESOURCES, - OBJECT_REQUEST_HELP, RUN_PLAY, - COLLAPSE_ALL, - EXPAND_ALL, - RUN_STOP, RUN_PLAY_SCENE, RUN_PLAY_NATIVE, @@ -195,8 +183,6 @@ private: IMPORT_PLUGIN_BASE = 100, - OBJECT_METHOD_BASE = 500, - TOOL_MENU_BASE = 1000 }; @@ -247,7 +233,6 @@ private: PopupMenu *tool_menu; ToolButton *export_button; ToolButton *prev_scene; - MenuButton *object_menu; ToolButton *play_button; MenuButton *native_play_button; ToolButton *pause_button; @@ -264,24 +249,13 @@ private: Ref<Theme> theme; PopupMenu *recent_scenes; - Button *property_back; - Button *property_forward; SceneTreeDock *scene_tree_dock; - EditorInspector *inspector; - Button *property_editable_warning; - AcceptDialog *property_editable_warning_dialog; - void _property_editable_warning_pressed(); + InspectorDock *inspector_dock; NodeDock *node_dock; ImportDock *import_dock; - VBoxContainer *prop_editor_vb; FileSystemDock *filesystem_dock; EditorRunNative *run_native; - HBoxContainer *search_bar; - LineEdit *search_box; - - CreateDialog *create_dialog; - ConfirmationDialog *confirmation; ConfirmationDialog *save_confirmation; ConfirmationDialog *import_confirmation; @@ -314,11 +288,6 @@ private: String defer_export_platform; bool defer_export_debug; Node *_last_instanced_scene; - EditorPath *editor_path; - ToolButton *resource_new_button; - ToolButton *resource_load_button; - MenuButton *resource_save_button; - MenuButton *editor_history_menu; EditorLog *log; CenterContainer *tabs_center; @@ -422,23 +391,12 @@ private: void _dialog_display_load_error(String p_file, Error p_error); int current_option; - void _resource_created(); - void _resource_selected(const RES &p_res, const String &p_property = ""); void _menu_option(int p_option); void _menu_confirm_current(); void _menu_option_confirm(int p_option, bool p_confirmed); void _tool_menu_option(int p_idx); void _update_debug_options(); - void _property_editor_forward(); - void _property_editor_back(); - - void _menu_collapseall(); - void _menu_expandall(); - - void _select_history(int p_idx); - void _prepare_history(); - void _fs_changed(); void _resources_reimported(const Vector<String> &p_resources); void _sources_changed(bool p_exist); @@ -462,9 +420,6 @@ private: void _instance_request(const Vector<String> &p_files); - void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance); - void _transform_keyed(Object *sp, const String &p_sub, const Transform &p_key); - void _hide_top_editors(); void _display_top_editors(bool p_display); void _set_top_editors(Vector<EditorPlugin *> p_editor_plugins_over); @@ -578,8 +533,6 @@ private: void _update_layouts_menu(); void _layout_menu_option(int p_id); - void _toggle_search_bar(bool p_pressed); - void _clear_search_box(); void _clear_undo_history(); void _update_addon_config(); @@ -640,8 +593,8 @@ public: EditorPluginList *get_editor_plugins_over() { return editor_plugins_over; } EditorPluginList *get_editor_plugins_force_over() { return editor_plugins_force_over; } EditorPluginList *get_editor_plugins_force_input_forwarding() { return editor_plugins_force_input_forwarding; } - EditorInspector *get_inspector() { return inspector; } - VBoxContainer *get_property_editor_vb() { return prop_editor_vb; } + EditorInspector *get_inspector() { return inspector_dock->get_inspector(); } + Container *get_inspector_dock_addon_area() { return inspector_dock->get_addon_area(); } ProjectSettingsEditor *get_project_settings() { return project_settings; } @@ -663,8 +616,8 @@ public: bool is_addon_plugin_enabled(const String &p_addon) const; void edit_node(Node *p_node); - void edit_resource(const Ref<Resource> &p_resource); - void open_resource(const String &p_type = ""); + void edit_resource(const Ref<Resource> &p_resource) { inspector_dock->edit_resource(p_resource); }; + void open_resource(const String &p_type) { inspector_dock->open_resource(p_type); }; void save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path); void save_resource(const Ref<Resource> &p_resource); @@ -713,6 +666,7 @@ public: FileSystemDock *get_filesystem_dock(); ImportDock *get_import_dock(); SceneTreeDock *get_scene_tree_dock(); + InspectorDock *get_inspector_dock(); static UndoRedo *get_undo_redo() { return &singleton->editor_data.get_undo_redo(); } EditorSelection *get_editor_selection() { return editor_selection; } @@ -759,8 +713,6 @@ public: void save_layout(); - void update_keying(); - void open_export_template_manager(); void reload_scene(const String &p_path); @@ -785,6 +737,10 @@ public: void dim_editor(bool p_dimming); + void edit_current() { _edit_current(); }; + + void update_keying() const { inspector_dock->update_keying(); }; + EditorNode(); ~EditorNode(); void get_singleton(const char *arg1, bool arg2); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index 2e4e887165..24d0592ee7 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -375,7 +375,7 @@ void EditorPlugin::add_control_to_container(CustomControlContainer p_location, C } break; case CONTAINER_PROPERTY_EDITOR_BOTTOM: { - EditorNode::get_singleton()->get_property_editor_vb()->add_child(p_control); + EditorNode::get_singleton()->get_inspector_dock_addon_area()->add_child(p_control); } break; } @@ -422,7 +422,7 @@ void EditorPlugin::remove_control_from_container(CustomControlContainer p_locati } break; case CONTAINER_PROPERTY_EDITOR_BOTTOM: { - EditorNode::get_singleton()->get_property_editor_vb()->remove_child(p_control); + EditorNode::get_singleton()->get_inspector_dock_addon_area()->remove_child(p_control); } break; } @@ -659,6 +659,14 @@ void EditorPlugin::remove_export_plugin(const Ref<EditorExportPlugin> &p_exporte EditorExport::get_singleton()->remove_export_plugin(p_exporter); } +void EditorPlugin::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) { + EditorInspector::add_inspector_plugin(p_plugin); +} + +void EditorPlugin::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) { + EditorInspector::remove_inspector_plugin(p_plugin); +} + void EditorPlugin::add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer) { ResourceImporterScene::get_singleton()->add_importer(p_importer); } @@ -728,8 +736,10 @@ void EditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_import_plugin", "importer"), &EditorPlugin::remove_import_plugin); ClassDB::bind_method(D_METHOD("add_scene_import_plugin", "scene_importer"), &EditorPlugin::add_scene_import_plugin); ClassDB::bind_method(D_METHOD("remove_scene_import_plugin", "scene_importer"), &EditorPlugin::remove_scene_import_plugin); - ClassDB::bind_method(D_METHOD("add_export_plugin", "exporter"), &EditorPlugin::add_export_plugin); - ClassDB::bind_method(D_METHOD("remove_export_plugin", "exporter"), &EditorPlugin::remove_export_plugin); + ClassDB::bind_method(D_METHOD("add_export_plugin", "plugin"), &EditorPlugin::add_export_plugin); + ClassDB::bind_method(D_METHOD("remove_export_plugin", "plugin"), &EditorPlugin::remove_export_plugin); + ClassDB::bind_method(D_METHOD("add_inspector_plugin", "plugin"), &EditorPlugin::add_inspector_plugin); + ClassDB::bind_method(D_METHOD("remove_inspector_plugin", "plugin"), &EditorPlugin::remove_inspector_plugin); ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled); ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled); diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index ebc4afdfeb..8af7f83771 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -31,6 +31,7 @@ #ifndef EDITOR_PLUGIN_H #define EDITOR_PLUGIN_H +#include "editor/editor_inspector.h" #include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_scene.h" #include "io/config_file.h" @@ -210,6 +211,9 @@ public: void add_export_plugin(const Ref<EditorExportPlugin> &p_exporter); void remove_export_plugin(const Ref<EditorExportPlugin> &p_exporter); + void add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); + void remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin); + void add_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer); void remove_scene_import_plugin(const Ref<EditorSceneImporter> &p_importer); diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index f3397d7980..d1968468f8 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -31,7 +31,20 @@ #include "editor_properties.h" #include "editor/editor_resource_preview.h" #include "editor_node.h" +#include "editor_properties_array_dict.h" #include "scene/main/viewport.h" + +///////////////////// NULL ///////////////////////// + +void EditorPropertyNil::update_property() { +} + +EditorPropertyNil::EditorPropertyNil() { + Label *label = memnew(Label); + label->set_text("[null]"); + add_child(label); +} + ///////////////////// TEXT ///////////////////////// void EditorPropertyText::_text_changed(const String &p_string) { if (updating) @@ -118,8 +131,8 @@ void EditorPropertyMultilineText::_bind_methods() { EditorPropertyMultilineText::EditorPropertyMultilineText() { HBoxContainer *hb = memnew(HBoxContainer); - set_label_layout(LABEL_LAYOUT_TOP); add_child(hb); + set_bottom_editor(hb); text = memnew(TextEdit); text->connect("text_changed", this, "_text_changed"); add_focusable(text); @@ -622,6 +635,7 @@ void EditorPropertyLayers::_button_pressed() { } Rect2 gp = button->get_global_rect(); + layers->set_as_minsize(); Vector2 popup_pos = gp.position - Vector2(layers->get_combined_minimum_size().x, 0); layers->set_global_position(popup_pos); layers->popup(); @@ -656,7 +670,7 @@ EditorPropertyLayers::EditorPropertyLayers() { button->set_text(".."); button->connect("pressed", this, "_button_pressed"); hb->add_child(button); - set_label_layout(LABEL_LAYOUT_TOP); + set_bottom_editor(hb); layers = memnew(PopupMenu); add_child(layers); layers->connect("id_pressed", this, "_menu_pressed"); @@ -1267,8 +1281,7 @@ EditorPropertyAABB::EditorPropertyAABB() { add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); } - set_label_reference(spin[0]); //show text and buttons around this - set_label_layout(LABEL_LAYOUT_TOP); + set_bottom_editor(g); setting = false; } @@ -1330,8 +1343,7 @@ EditorPropertyTransform2D::EditorPropertyTransform2D() { add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); } - set_label_reference(spin[0]); //show text and buttons around this - set_label_layout(LABEL_LAYOUT_TOP); + set_bottom_editor(g); setting = false; } @@ -1399,8 +1411,7 @@ EditorPropertyBasis::EditorPropertyBasis() { add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); } - set_label_reference(spin[0]); //show text and buttons around this - set_label_layout(LABEL_LAYOUT_TOP); + set_bottom_editor(g); setting = false; } @@ -1474,8 +1485,7 @@ EditorPropertyTransform::EditorPropertyTransform() { add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); } - set_label_reference(spin[0]); //show text and buttons around this - set_label_layout(LABEL_LAYOUT_TOP); + set_bottom_editor(g); setting = false; } @@ -1512,7 +1522,8 @@ EditorPropertyColor::EditorPropertyColor() { void EditorPropertyNodePath::_node_selected(const NodePath &p_path) { - emit_signal("property_changed", get_edited_property(), p_path); + Node *base_node = Object::cast_to<Node>(get_edited_object()); + emit_signal("property_changed", get_edited_property(), base_node->get_path().rel_path_to(p_path)); update_property(); } @@ -1952,23 +1963,75 @@ void EditorPropertyResource::_update_menu() { } } - Rect2 gt = get_global_rect(); + Rect2 gt = edit->get_global_rect(); + menu->set_as_minsize(); int ms = menu->get_combined_minimum_size().width; Vector2 popup_pos = gt.position + gt.size - Vector2(ms, 0); - menu->set_position(popup_pos); + menu->set_global_position(popup_pos); menu->popup(); } +void EditorPropertyResource::_sub_inspector_property_keyed(const String &p_property, const Variant &p_value, bool) { + + emit_signal("property_keyed_with_value", String(get_edited_property()) + ":" + p_property, p_value); +} + +void EditorPropertyResource::_sub_inspector_resource_selected(const RES &p_resource, const String &p_property) { + + emit_signal("resource_selected", String(get_edited_property()) + ":" + p_property, p_resource); +} + +void EditorPropertyResource::_sub_inspector_object_id_selected(int p_id) { + + emit_signal("object_id_selected", get_edited_property(), p_id); +} + void EditorPropertyResource::update_property() { RES res = get_edited_object()->get(get_edited_property()); + if (use_sub_inspector) { + + if (res.is_valid() != assign->is_toggle_mode()) { + assign->set_toggle_mode(res.is_valid()); + } +#ifdef TOOLS_ENABLED + if (res.is_valid() && get_edited_object()->editor_is_section_unfolded(get_edited_property())) { + + if (!sub_inspector) { + sub_inspector = memnew(EditorInspector); + sub_inspector->set_enable_v_scroll(false); + + sub_inspector->connect("property_keyed", this, "_sub_inspector_property_keyed"); + sub_inspector->connect("resource_selected", this, "_sub_inspector_resource_selected"); + sub_inspector->connect("object_id_selected", this, "_sub_inspector_object_id_selected"); + sub_inspector->set_keying(is_keying()); + sub_inspector->set_read_only(is_read_only()); + sub_inspector->set_use_folding(is_using_folding()); + + add_child(sub_inspector); + set_bottom_editor(sub_inspector); + assign->set_pressed(true); + } + + if (res.ptr() != sub_inspector->get_edited_object()) { + sub_inspector->edit(res.ptr()); + } + + } else { + if (sub_inspector) { + set_bottom_editor(NULL); + memdelete(sub_inspector); + sub_inspector = NULL; + } + } +#endif + } + if (res == RES()) { assign->set_icon(Ref<Texture>()); assign->set_text(TTR("[empty]")); - assign->set_disabled(true); } else { - assign->set_disabled(false); Ref<Texture> icon; if (has_icon(res->get_class(), "EditorIcons")) @@ -1999,7 +2062,16 @@ void EditorPropertyResource::update_property() { void EditorPropertyResource::_resource_selected() { RES res = get_edited_object()->get(get_edited_property()); - if (!res.is_null()) { + if (res.is_null()) { + _update_menu(); + return; + } + + if (use_sub_inspector) { + + get_edited_object()->editor_set_section_unfold(get_edited_property(), assign->is_pressed()); + update_property(); + } else { emit_signal("resource_selected", get_edited_property(), res); } @@ -2015,6 +2087,23 @@ void EditorPropertyResource::_notification(int p_what) { Ref<Texture> t = get_icon("select_arrow", "Tree"); edit->set_icon(t); } + + if (p_what == NOTIFICATION_DRAG_BEGIN) { + + if (is_visible_in_tree()) { + if (_is_drop_valid(get_viewport()->gui_get_drag_data())) { + dropping = true; + assign->update(); + } + } + } + + if (p_what == NOTIFICATION_DRAG_END) { + if (dropping) { + dropping = false; + assign->update(); + } + } } void EditorPropertyResource::_viewport_selected(const NodePath &p_path) { @@ -2033,6 +2122,111 @@ void EditorPropertyResource::_viewport_selected(const NodePath &p_path) { emit_signal("property_changed", get_edited_property(), vt); update_property(); } + +void EditorPropertyResource::collapse_all_folding() { + if (sub_inspector) { + sub_inspector->collapse_all_folding(); + } +} + +void EditorPropertyResource::expand_all_folding() { + + if (sub_inspector) { + sub_inspector->expand_all_folding(); + } +} + +void EditorPropertyResource::_button_draw() { + + if (dropping) { + Color color = get_color("accent_color", "Editor"); + assign->draw_rect(Rect2(Point2(), assign->get_size()), color, false); + } +} + +Variant EditorPropertyResource::get_drag_data_fw(const Point2 &p_point, Control *p_from) { + + RES res = get_edited_object()->get(get_edited_property()); + if (res.is_valid()) { + + return EditorNode::get_singleton()->drag_resource(res, p_from); + } + + return Variant(); +} + +bool EditorPropertyResource::_is_drop_valid(const Dictionary &p_drag_data) const { + + String allowed_type = base_type; + + Dictionary drag_data = p_drag_data; + if (drag_data.has("type") && String(drag_data["type"]) == "resource") { + Ref<Resource> res = drag_data["resource"]; + for (int i = 0; i < allowed_type.get_slice_count(","); i++) { + String at = allowed_type.get_slice(",", i).strip_edges(); + if (res.is_valid() && ClassDB::is_parent_class(res->get_class(), at)) { + return true; + } + } + } + + if (drag_data.has("type") && String(drag_data["type"]) == "files") { + + Vector<String> files = drag_data["files"]; + + if (files.size() == 1) { + String file = files[0]; + String ftype = EditorFileSystem::get_singleton()->get_file_type(file); + + if (ftype != "") { + + for (int i = 0; i < allowed_type.get_slice_count(","); i++) { + String at = allowed_type.get_slice(",", i).strip_edges(); + if (ClassDB::is_parent_class(ftype, at)) { + return true; + } + } + } + } + } + + return false; +} + +bool EditorPropertyResource::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const { + + return _is_drop_valid(p_data); +} +void EditorPropertyResource::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { + + ERR_FAIL_COND(!_is_drop_valid(p_data)); + + Dictionary drag_data = p_data; + if (drag_data.has("type") && String(drag_data["type"]) == "resource") { + Ref<Resource> res = drag_data["resource"]; + if (res.is_valid()) { + emit_signal("property_changed", get_edited_property(), res); + update_property(); + return; + } + } + + if (drag_data.has("type") && String(drag_data["type"]) == "files") { + + Vector<String> files = drag_data["files"]; + + if (files.size() == 1) { + String file = files[0]; + RES res = ResourceLoader::load(file); + if (res.is_valid()) { + emit_signal("property_changed", get_edited_property(), res); + update_property(); + return; + } + } + } +} + void EditorPropertyResource::_bind_methods() { ClassDB::bind_method(D_METHOD("_file_selected"), &EditorPropertyResource::_file_selected); @@ -2041,10 +2235,19 @@ void EditorPropertyResource::_bind_methods() { ClassDB::bind_method(D_METHOD("_resource_preview"), &EditorPropertyResource::_resource_preview); ClassDB::bind_method(D_METHOD("_resource_selected"), &EditorPropertyResource::_resource_selected); ClassDB::bind_method(D_METHOD("_viewport_selected"), &EditorPropertyResource::_viewport_selected); + ClassDB::bind_method(D_METHOD("_sub_inspector_property_keyed"), &EditorPropertyResource::_sub_inspector_property_keyed); + ClassDB::bind_method(D_METHOD("_sub_inspector_resource_selected"), &EditorPropertyResource::_sub_inspector_resource_selected); + ClassDB::bind_method(D_METHOD("_sub_inspector_object_id_selected"), &EditorPropertyResource::_sub_inspector_object_id_selected); + ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &EditorPropertyResource::get_drag_data_fw); + ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &EditorPropertyResource::can_drop_data_fw); + ClassDB::bind_method(D_METHOD("drop_data_fw"), &EditorPropertyResource::drop_data_fw); + ClassDB::bind_method(D_METHOD("_button_draw"), &EditorPropertyResource::_button_draw); } EditorPropertyResource::EditorPropertyResource() { + sub_inspector = NULL; + use_sub_inspector = !bool(EDITOR_GET("interface/inspector/open_resources_in_new_inspector")); HBoxContainer *hbc = memnew(HBoxContainer); add_child(hbc); assign = memnew(Button); @@ -2052,6 +2255,8 @@ EditorPropertyResource::EditorPropertyResource() { assign->set_h_size_flags(SIZE_EXPAND_FILL); assign->set_clip_text(true); assign->connect("pressed", this, "_resource_selected"); + assign->set_drag_forwarding(this); + assign->connect("draw", this, "_button_draw"); hbc->add_child(assign); menu = memnew(PopupMenu); @@ -2064,6 +2269,7 @@ EditorPropertyResource::EditorPropertyResource() { file = NULL; scene_tree = NULL; + dropping = false; } ////////////// DEFAULT PLUGIN ////////////////////// @@ -2081,6 +2287,10 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ switch (p_type) { // atomic types + case Variant::NIL: { + EditorPropertyNil *editor = memnew(EditorPropertyNil); + add_property_editor(p_path, editor); + } break; case Variant::BOOL: { EditorPropertyCheck *editor = memnew(EditorPropertyCheck); add_property_editor(p_path, editor); @@ -2439,24 +2649,40 @@ bool EditorInspectorDefaultPlugin::parse_property(Object *p_object, Variant::Typ } break; case Variant::DICTIONARY: { + EditorPropertyDictionary *editor = memnew(EditorPropertyDictionary); + add_property_editor(p_path, editor); } break; case Variant::ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; - - // arrays case Variant::POOL_BYTE_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; // 20 case Variant::POOL_INT_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; case Variant::POOL_REAL_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; case Variant::POOL_STRING_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; case Variant::POOL_VECTOR2_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; case Variant::POOL_VECTOR3_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; // 25 case Variant::POOL_COLOR_ARRAY: { + EditorPropertyArray *editor = memnew(EditorPropertyArray); + add_property_editor(p_path, editor); } break; default: {} } diff --git a/editor/editor_properties.h b/editor/editor_properties.h index cf0c735b37..03e72b4ec2 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -39,6 +39,15 @@ #include "editor/scene_tree_editor.h" #include "scene/gui/color_picker.h" +class EditorPropertyNil : public EditorProperty { + GDCLASS(EditorPropertyNil, EditorProperty) + LineEdit *text; + +public: + virtual void update_property(); + EditorPropertyNil(); +}; + class EditorPropertyText : public EditorProperty { GDCLASS(EditorPropertyText, EditorProperty) LineEdit *text; @@ -481,7 +490,10 @@ class EditorPropertyResource : public EditorProperty { PopupMenu *menu; EditorFileDialog *file; Vector<String> inheritors_array; + EditorInspector *sub_inspector; + bool use_sub_inspector; + bool dropping; String base_type; SceneTreeDialog *scene_tree; @@ -494,6 +506,16 @@ class EditorPropertyResource : public EditorProperty { void _update_menu(); + void _sub_inspector_property_keyed(const String &p_property, const Variant &p_value, bool); + void _sub_inspector_resource_selected(const RES &p_resource, const String &p_property); + void _sub_inspector_object_id_selected(int p_id); + + void _button_draw(); + Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); + bool _is_drop_valid(const Dictionary &p_drag_data) const; + bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; + void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from); + protected: static void _bind_methods(); void _notification(int p_what); @@ -501,6 +523,10 @@ protected: public: virtual void update_property(); void setup(const String &p_base_type); + + void collapse_all_folding(); + void expand_all_folding(); + EditorPropertyResource(); }; diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp new file mode 100644 index 0000000000..90f8d0e157 --- /dev/null +++ b/editor/editor_properties_array_dict.cpp @@ -0,0 +1,999 @@ +#include "editor_properties_array_dict.h" +#include "editor/editor_scale.h" +#include "editor_properties.h" + +bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) { + + String pn = p_name; + + if (pn.begins_with("indices")) { + int idx = pn.get_slicec('/', 1).to_int(); + array.set(idx, p_value); + return true; + } + + return false; +} + +bool EditorPropertyArrayObject::_get(const StringName &p_name, Variant &r_ret) const { + + String pn = p_name; + + if (pn.begins_with("indices")) { + + int idx = pn.get_slicec('/', 1).to_int(); + bool valid; + r_ret = array.get(idx, &valid); + return valid; + } + + return false; +} + +void EditorPropertyArrayObject::set_array(const Variant &p_array) { + array = p_array; +} + +Variant EditorPropertyArrayObject::get_array() { + return array; +} + +EditorPropertyArrayObject::EditorPropertyArrayObject() { +} + +/////////////////// + +bool EditorPropertyDictionaryObject::_set(const StringName &p_name, const Variant &p_value) { + + String pn = p_name; + + if (pn == "new_item_key") { + + new_item_key = p_value; + return true; + } + + if (pn == "new_item_value") { + + new_item_value = p_value; + return true; + } + + if (pn.begins_with("indices")) { + int idx = pn.get_slicec('/', 1).to_int(); + Variant key = dict.get_key_at_index(idx); + dict[key] = p_value; + return true; + } + + return false; +} + +bool EditorPropertyDictionaryObject::_get(const StringName &p_name, Variant &r_ret) const { + + String pn = p_name; + + if (pn == "new_item_key") { + + r_ret = new_item_key; + return true; + } + + if (pn == "new_item_value") { + + r_ret = new_item_value; + return true; + } + + if (pn.begins_with("indices")) { + + int idx = pn.get_slicec('/', 1).to_int(); + Variant key = dict.get_key_at_index(idx); + r_ret = dict[key]; + return true; + } + + return false; +} + +void EditorPropertyDictionaryObject::set_dict(const Dictionary &p_dict) { + dict = p_dict; +} + +Dictionary EditorPropertyDictionaryObject::get_dict() { + return dict; +} + +void EditorPropertyDictionaryObject::set_new_item_key(const Variant &p_new_item) { + new_item_key = p_new_item; +} + +Variant EditorPropertyDictionaryObject::get_new_item_key() { + return new_item_key; +} + +void EditorPropertyDictionaryObject::set_new_item_value(const Variant &p_new_item) { + new_item_value = p_new_item; +} + +Variant EditorPropertyDictionaryObject::get_new_item_value() { + return new_item_value; +} + +EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() { +} + +///////////////////// ARRAY /////////////////////////// + +void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_value) { + + if (p_prop.begins_with("indices")) { + int idx = p_prop.get_slice("/", 1).to_int(); + Variant array = object->get_array(); + array.set(idx, p_value); + emit_signal("property_changed", get_edited_property(), array); + + if (array.get_type() == Variant::ARRAY) { + array = array.call("duplicate"); //dupe, so undo/redo works better + } + object->set_array(array); + } +} + +void EditorPropertyArray::_change_type(Object *p_button, int p_index) { + + Button *button = Object::cast_to<Button>(p_button); + + Rect2 rect = button->get_global_rect(); + change_type->set_as_minsize(); + change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0)); + change_type->popup(); + changing_type_idx = p_index; +} + +void EditorPropertyArray::_change_type_menu(int p_index) { + + Variant value; + Variant::CallError ce; + value = Variant::construct(Variant::Type(p_index), NULL, 0, ce); + Variant array = object->get_array(); + array.set(changing_type_idx, value); + + emit_signal("property_changed", get_edited_property(), array); + + if (array.get_type() == Variant::ARRAY) { + array = array.call("duplicate"); //dupe, so undo/redo works better + } + object->set_array(array); + update_property(); +} + +void EditorPropertyArray::update_property() { + + Variant array = get_edited_object()->get(get_edited_property()); + + if ((!array.is_array()) != edit->is_disabled()) { + + if (array.is_array()) { + edit->set_disabled(false); + edit->set_pressed(false); + + } else { + edit->set_disabled(true); + if (vbox) { + memdelete(vbox); + } + } + } + + if (!array.is_array()) { + return; + } + + String arrtype; + switch (array.get_type()) { + case Variant::ARRAY: { + + arrtype = "Array"; + + } break; + + // arrays + case Variant::POOL_BYTE_ARRAY: { + arrtype = "ByteArray"; + + } break; + case Variant::POOL_INT_ARRAY: { + arrtype = "IntArray"; + + } break; + case Variant::POOL_REAL_ARRAY: { + + arrtype = "FltArray"; + } break; + case Variant::POOL_STRING_ARRAY: { + + arrtype = "StrArray"; + } break; + case Variant::POOL_VECTOR2_ARRAY: { + + arrtype = "Vec2Array"; + } break; + case Variant::POOL_VECTOR3_ARRAY: { + arrtype = "Vec3Array"; + + } break; + case Variant::POOL_COLOR_ARRAY: { + arrtype = "ColArray"; + } break; + default: {} + } + + edit->set_text(arrtype + "[" + itos(array.call("size")) + "]"); + +#ifdef TOOLS_ENABLED + + bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); + if (edit->is_pressed() != unfolded) { + edit->set_pressed(unfolded); + } + + if (unfolded) { + + updating = true; + + if (!vbox) { + + vbox = memnew(VBoxContainer); + add_child(vbox); + set_bottom_editor(vbox); + HBoxContainer *hbc = memnew(HBoxContainer); + vbox->add_child(hbc); + Label *label = memnew(Label(TTR("Size: "))); + label->set_h_size_flags(SIZE_EXPAND_FILL); + hbc->add_child(label); + length = memnew(EditorSpinSlider); + length->set_step(1); + length->set_max(1000000); + length->set_h_size_flags(SIZE_EXPAND_FILL); + hbc->add_child(length); + length->connect("value_changed", this, "_length_changed"); + + page_hb = memnew(HBoxContainer); + vbox->add_child(page_hb); + label = memnew(Label(TTR("Page: "))); + label->set_h_size_flags(SIZE_EXPAND_FILL); + page_hb->add_child(label); + page = memnew(EditorSpinSlider); + page->set_step(1); + page_hb->add_child(page); + page->set_h_size_flags(SIZE_EXPAND_FILL); + page->connect("value_changed", this, "_page_changed"); + } else { + //bye bye children of the box + while (vbox->get_child_count() > 2) { + memdelete(vbox->get_child(2)); + } + } + + int len = array.call("size"); + + length->set_value(len); + + int pages = MAX(0, len - 1) / page_len + 1; + + page->set_max(pages); + page_idx = MIN(page_idx, pages - 1); + page->set_value(page_idx); + page_hb->set_visible(pages > 1); + + int offset = page_idx * page_len; + + int amount = MIN(len - offset, page_len); + + if (array.get_type() == Variant::ARRAY) { + array = array.call("duplicate"); + } + + object->set_array(array); + + for (int i = 0; i < amount; i++) { + String prop_name = "indices/" + itos(i + offset); + + EditorProperty *prop = NULL; + Variant value = array.get(i + offset); + + switch (value.get_type()) { + case Variant::NIL: { + prop = memnew(EditorPropertyNil); + + } break; + + // atomic types + case Variant::BOOL: { + + prop = memnew(EditorPropertyCheck); + + } break; + case Variant::INT: { + EditorPropertyInteger *ed = memnew(EditorPropertyInteger); + ed->setup(-100000, 100000, true, true); + prop = ed; + + } break; + case Variant::REAL: { + + EditorPropertyFloat *ed = memnew(EditorPropertyFloat); + ed->setup(-100000, 100000, 0.001, true, false, true, true); + prop = ed; + } break; + case Variant::STRING: { + + prop = memnew(EditorPropertyText); + + } break; + + // math types + + case Variant::VECTOR2: { + + EditorPropertyVector2 *ed = memnew(EditorPropertyVector2); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::RECT2: { + + EditorPropertyRect2 *ed = memnew(EditorPropertyRect2); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::VECTOR3: { + + EditorPropertyVector3 *ed = memnew(EditorPropertyVector3); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::TRANSFORM2D: { + + EditorPropertyTransform2D *ed = memnew(EditorPropertyTransform2D); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::PLANE: { + + EditorPropertyPlane *ed = memnew(EditorPropertyPlane); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::QUAT: { + + EditorPropertyQuat *ed = memnew(EditorPropertyQuat); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::AABB: { + + EditorPropertyAABB *ed = memnew(EditorPropertyAABB); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::BASIS: { + EditorPropertyBasis *ed = memnew(EditorPropertyBasis); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::TRANSFORM: { + EditorPropertyTransform *ed = memnew(EditorPropertyTransform); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + + // misc types + case Variant::COLOR: { + prop = memnew(EditorPropertyColor); + + } break; + case Variant::NODE_PATH: { + prop = memnew(EditorPropertyNodePath); + + } break; + case Variant::_RID: { + prop = memnew(EditorPropertyNil); + + } break; + case Variant::OBJECT: { + + prop = memnew(EditorPropertyResource); + + } break; + case Variant::DICTIONARY: { + prop = memnew(EditorPropertyDictionary); + + } break; + case Variant::ARRAY: { + + prop = memnew(EditorPropertyArray); + + } break; + + // arrays + case Variant::POOL_BYTE_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + case Variant::POOL_INT_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + case Variant::POOL_REAL_ARRAY: { + + prop = memnew(EditorPropertyArray); + } break; + case Variant::POOL_STRING_ARRAY: { + + prop = memnew(EditorPropertyArray); + } break; + case Variant::POOL_VECTOR2_ARRAY: { + + prop = memnew(EditorPropertyArray); + } break; + case Variant::POOL_VECTOR3_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + case Variant::POOL_COLOR_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + default: {} + } + + prop->set_object_and_property(object.ptr(), prop_name); + prop->set_label(itos(i + offset)); + prop->set_selectable(false); + prop->connect("property_changed", this, "_property_changed"); + if (array.get_type() == Variant::ARRAY) { + HBoxContainer *hb = memnew(HBoxContainer); + vbox->add_child(hb); + hb->add_child(prop); + prop->set_h_size_flags(SIZE_EXPAND_FILL); + Button *edit = memnew(Button); + edit->set_icon(get_icon("Edit", "EditorIcons")); + hb->add_child(edit); + edit->connect("pressed", this, "_change_type", varray(edit, i + offset)); + } else { + vbox->add_child(prop); + } + + prop->update_property(); + } + + updating = false; + + } else { + if (vbox) { + set_bottom_editor(NULL); + memdelete(vbox); + vbox = NULL; + } + } +#endif +} + +void EditorPropertyArray::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + } +} +void EditorPropertyArray::_edit_pressed() { + + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); + update_property(); +} + +void EditorPropertyArray::_page_changed(double p_page) { + if (updating) + return; + page_idx = p_page; + update_property(); +} + +void EditorPropertyArray::_length_changed(double p_page) { + if (updating) + return; + + Variant array = object->get_array(); + array.call("resize", int(p_page)); + emit_signal("property_changed", get_edited_property(), array); + + if (array.get_type() == Variant::ARRAY) { + array = array.call("duplicate"); //dupe, so undo/redo works better + } + object->set_array(array); + update_property(); +} + +void EditorPropertyArray::_bind_methods() { + ClassDB::bind_method("_edit_pressed", &EditorPropertyArray::_edit_pressed); + ClassDB::bind_method("_page_changed", &EditorPropertyArray::_page_changed); + ClassDB::bind_method("_length_changed", &EditorPropertyArray::_length_changed); + ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed); + ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type); + ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu); +} + +EditorPropertyArray::EditorPropertyArray() { + + object.instance(); + page_idx = 0; + page_len = 10; + edit = memnew(Button); + edit->set_flat(true); + edit->set_h_size_flags(SIZE_EXPAND_FILL); + edit->set_clip_text(true); + edit->connect("pressed", this, "_edit_pressed"); + edit->set_toggle_mode(true); + add_child(edit); + add_focusable(edit); + vbox = NULL; + page = NULL; + length = NULL; + updating = false; + change_type = memnew(PopupMenu); + add_child(change_type); + change_type->connect("id_pressed", this, "_change_type_menu"); + changing_type_idx = -1; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + String type = Variant::get_type_name(Variant::Type(i)); + change_type->add_item(type, i); + } + changing_type_idx = -1; +} + +///////////////////// DICTIONARY /////////////////////////// + +void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value) { + + if (p_prop == "new_item_key") { + + object->set_new_item_key(p_value); + } else if (p_prop == "new_item_value") { + + object->set_new_item_value(p_value); + } else if (p_prop.begins_with("indices")) { + int idx = p_prop.get_slice("/", 1).to_int(); + Dictionary dict = object->get_dict(); + Variant key = dict.get_key_at_index(idx); + dict[key] = p_value; + + emit_signal("property_changed", get_edited_property(), dict); + + dict = dict.duplicate(); //dupe, so undo/redo works better + object->set_dict(dict); + } +} + +void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) { + + Button *button = Object::cast_to<Button>(p_button); + + Rect2 rect = button->get_global_rect(); + change_type->set_as_minsize(); + change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0)); + change_type->popup(); + changing_type_idx = p_index; +} + +void EditorPropertyDictionary::_add_key_value() { + + Dictionary dict = object->get_dict(); + dict[object->get_new_item_key()] = object->get_new_item_value(); + object->set_new_item_key(Variant()); + object->set_new_item_value(Variant()); + + emit_signal("property_changed", get_edited_property(), dict); + + dict = dict.duplicate(); //dupe, so undo/redo works better + object->set_dict(dict); + update_property(); +} + +void EditorPropertyDictionary::_change_type_menu(int p_index) { + + if (changing_type_idx < 0) { + Variant value; + Variant::CallError ce; + value = Variant::construct(Variant::Type(p_index), NULL, 0, ce); + if (changing_type_idx == -1) { + object->set_new_item_key(value); + } else { + object->set_new_item_value(value); + } + update_property(); + return; + } + + Dictionary dict = object->get_dict(); + + if (p_index < Variant::VARIANT_MAX) { + + Variant value; + Variant::CallError ce; + value = Variant::construct(Variant::Type(p_index), NULL, 0, ce); + Variant key = dict.get_key_at_index(changing_type_idx); + dict[key] = value; + } else { + Variant key = dict.get_key_at_index(changing_type_idx); + dict.erase(key); + } + + emit_signal("property_changed", get_edited_property(), dict); + + dict = dict.duplicate(); //dupe, so undo/redo works better + object->set_dict(dict); + update_property(); +} + +void EditorPropertyDictionary::update_property() { + + Dictionary dict = get_edited_object()->get(get_edited_property()); + + edit->set_text("Dict[" + itos(dict.size()) + "]"); + +#ifdef TOOLS_ENABLED + + bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property()); + if (edit->is_pressed() != unfolded) { + edit->set_pressed(unfolded); + } + + if (unfolded) { + + updating = true; + + if (!vbox) { + + vbox = memnew(VBoxContainer); + add_child(vbox); + set_bottom_editor(vbox); + + page_hb = memnew(HBoxContainer); + vbox->add_child(page_hb); + Label *label = memnew(Label(TTR("Page: "))); + label->set_h_size_flags(SIZE_EXPAND_FILL); + page_hb->add_child(label); + page = memnew(EditorSpinSlider); + page->set_step(1); + page_hb->add_child(page); + page->set_h_size_flags(SIZE_EXPAND_FILL); + page->connect("value_changed", this, "_page_changed"); + } else { + //bye bye children of the box + while (vbox->get_child_count() > 1) { + memdelete(vbox->get_child(1)); + } + } + + int len = dict.size(); + + int pages = MAX(0, len - 1) / page_len + 1; + + page->set_max(pages); + page_idx = MIN(page_idx, pages - 1); + page->set_value(page_idx); + page_hb->set_visible(pages > 1); + + int offset = page_idx * page_len; + + int amount = MIN(len - offset, page_len); + + dict = dict.duplicate(); + + object->set_dict(dict); + VBoxContainer *add_vbox = NULL; + + for (int i = 0; i < amount + 2; i++) { + String prop_name; + Variant key; + Variant value; + + if (i < amount) { + prop_name = "indices/" + itos(i + offset); + key = dict.get_key_at_index(i + offset); + value = dict.get_value_at_index(i + offset); + } else if (i == amount) { + prop_name = "new_item_key"; + value = object->get_new_item_key(); + } else if (i == amount + 1) { + prop_name = "new_item_value"; + value = object->get_new_item_value(); + } + + EditorProperty *prop = NULL; + + switch (value.get_type()) { + case Variant::NIL: { + prop = memnew(EditorPropertyNil); + + } break; + + // atomic types + case Variant::BOOL: { + + prop = memnew(EditorPropertyCheck); + + } break; + case Variant::INT: { + EditorPropertyInteger *ed = memnew(EditorPropertyInteger); + ed->setup(-100000, 100000, true, true); + prop = ed; + + } break; + case Variant::REAL: { + + EditorPropertyFloat *ed = memnew(EditorPropertyFloat); + ed->setup(-100000, 100000, 0.001, true, false, true, true); + prop = ed; + } break; + case Variant::STRING: { + + prop = memnew(EditorPropertyText); + + } break; + + // math types + + case Variant::VECTOR2: { + + EditorPropertyVector2 *ed = memnew(EditorPropertyVector2); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::RECT2: { + + EditorPropertyRect2 *ed = memnew(EditorPropertyRect2); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::VECTOR3: { + + EditorPropertyVector3 *ed = memnew(EditorPropertyVector3); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::TRANSFORM2D: { + + EditorPropertyTransform2D *ed = memnew(EditorPropertyTransform2D); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::PLANE: { + + EditorPropertyPlane *ed = memnew(EditorPropertyPlane); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::QUAT: { + + EditorPropertyQuat *ed = memnew(EditorPropertyQuat); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::AABB: { + + EditorPropertyAABB *ed = memnew(EditorPropertyAABB); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::BASIS: { + EditorPropertyBasis *ed = memnew(EditorPropertyBasis); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + case Variant::TRANSFORM: { + EditorPropertyTransform *ed = memnew(EditorPropertyTransform); + ed->setup(-100000, 100000, 0.001, true); + prop = ed; + + } break; + + // misc types + case Variant::COLOR: { + prop = memnew(EditorPropertyColor); + + } break; + case Variant::NODE_PATH: { + prop = memnew(EditorPropertyNodePath); + + } break; + case Variant::_RID: { + prop = memnew(EditorPropertyNil); + + } break; + case Variant::OBJECT: { + + prop = memnew(EditorPropertyResource); + + } break; + case Variant::DICTIONARY: { + prop = memnew(EditorPropertyDictionary); + + } break; + case Variant::ARRAY: { + + prop = memnew(EditorPropertyArray); + + } break; + + // arrays + case Variant::POOL_BYTE_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + case Variant::POOL_INT_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + case Variant::POOL_REAL_ARRAY: { + + prop = memnew(EditorPropertyArray); + } break; + case Variant::POOL_STRING_ARRAY: { + + prop = memnew(EditorPropertyArray); + } break; + case Variant::POOL_VECTOR2_ARRAY: { + + prop = memnew(EditorPropertyArray); + } break; + case Variant::POOL_VECTOR3_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + case Variant::POOL_COLOR_ARRAY: { + prop = memnew(EditorPropertyArray); + + } break; + default: {} + } + + if (i == amount) { + PanelContainer *pc = memnew(PanelContainer); + vbox->add_child(pc); + Ref<StyleBoxFlat> flat; + flat.instance(); + for (int j = 0; j < 4; j++) { + flat->set_default_margin(Margin(j), 2 * EDSCALE); + } + flat->set_bg_color(get_color("prop_subsection", "Editor")); + + pc->add_style_override("panel", flat); + add_vbox = memnew(VBoxContainer); + pc->add_child(add_vbox); + } + prop->set_object_and_property(object.ptr(), prop_name); + int change_index; + + if (i < amount) { + String cs = key.get_construct_string(); + prop->set_label(key.get_construct_string()); + prop->set_tooltip(cs); + change_index = i + offset; + } else if (i == amount) { + prop->set_label(TTR("New Key:")); + change_index = -1; + } else if (i == amount + 1) { + prop->set_label(TTR("New Value:")); + change_index = -2; + } + + prop->set_selectable(false); + prop->connect("property_changed", this, "_property_changed"); + + HBoxContainer *hb = memnew(HBoxContainer); + if (add_vbox) { + add_vbox->add_child(hb); + } else { + vbox->add_child(hb); + } + hb->add_child(prop); + prop->set_h_size_flags(SIZE_EXPAND_FILL); + Button *edit = memnew(Button); + edit->set_icon(get_icon("Edit", "EditorIcons")); + hb->add_child(edit); + edit->connect("pressed", this, "_change_type", varray(edit, change_index)); + + prop->update_property(); + + if (i == amount + 1) { + Button *add_item = memnew(Button); + add_item->set_text(TTR("Add Key/Value Pair")); + add_vbox->add_child(add_item); + add_item->connect("pressed", this, "_add_key_value"); + } + } + + updating = false; + + } else { + if (vbox) { + set_bottom_editor(NULL); + memdelete(vbox); + vbox = NULL; + } + } +#endif +} + +void EditorPropertyDictionary::_notification(int p_what) { + + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + } +} +void EditorPropertyDictionary::_edit_pressed() { + + get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed()); + update_property(); +} + +void EditorPropertyDictionary::_page_changed(double p_page) { + if (updating) + return; + page_idx = p_page; + update_property(); +} + +void EditorPropertyDictionary::_bind_methods() { + ClassDB::bind_method("_edit_pressed", &EditorPropertyDictionary::_edit_pressed); + ClassDB::bind_method("_page_changed", &EditorPropertyDictionary::_page_changed); + ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed); + ClassDB::bind_method("_change_type", &EditorPropertyDictionary::_change_type); + ClassDB::bind_method("_change_type_menu", &EditorPropertyDictionary::_change_type_menu); + ClassDB::bind_method("_add_key_value", &EditorPropertyDictionary::_add_key_value); +} + +EditorPropertyDictionary::EditorPropertyDictionary() { + + object.instance(); + page_idx = 0; + page_len = 10; + edit = memnew(Button); + edit->set_flat(true); + edit->set_h_size_flags(SIZE_EXPAND_FILL); + edit->set_clip_text(true); + edit->connect("pressed", this, "_edit_pressed"); + edit->set_toggle_mode(true); + add_child(edit); + add_focusable(edit); + vbox = NULL; + page = NULL; + updating = false; + change_type = memnew(PopupMenu); + add_child(change_type); + change_type->connect("id_pressed", this, "_change_type_menu"); + changing_type_idx = -1; + for (int i = 0; i < Variant::VARIANT_MAX; i++) { + String type = Variant::get_type_name(Variant::Type(i)); + change_type->add_item(type, i); + } + change_type->add_separator(); + change_type->add_item(TTR("Remove Item"), Variant::VARIANT_MAX); + changing_type_idx = -1; +} diff --git a/editor/editor_properties_array_dict.h b/editor/editor_properties_array_dict.h new file mode 100644 index 0000000000..7f6203ee88 --- /dev/null +++ b/editor/editor_properties_array_dict.h @@ -0,0 +1,115 @@ +#ifndef EDITOR_PROPERTIES_ARRAY_DICT_H +#define EDITOR_PROPERTIES_ARRAY_DICT_H + +#include "editor/editor_inspector.h" +#include "editor/editor_spin_slider.h" +#include "scene/gui/button.h" + +class EditorPropertyArrayObject : public Reference { + + GDCLASS(EditorPropertyArrayObject, Reference); + + Variant array; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + +public: + void set_array(const Variant &p_array); + Variant get_array(); + + EditorPropertyArrayObject(); +}; + +class EditorPropertyDictionaryObject : public Reference { + + GDCLASS(EditorPropertyDictionaryObject, Reference); + + Variant new_item_key; + Variant new_item_value; + Dictionary dict; + +protected: + bool _set(const StringName &p_name, const Variant &p_value); + bool _get(const StringName &p_name, Variant &r_ret) const; + +public: + void set_dict(const Dictionary &p_dict); + Dictionary get_dict(); + + void set_new_item_key(const Variant &p_new_item); + Variant get_new_item_key(); + + void set_new_item_value(const Variant &p_new_item); + Variant get_new_item_value(); + + EditorPropertyDictionaryObject(); +}; + +class EditorPropertyArray : public EditorProperty { + GDCLASS(EditorPropertyArray, EditorProperty) + + PopupMenu *change_type; + bool updating; + + Ref<EditorPropertyArrayObject> object; + int page_len; + int page_idx; + int changing_type_idx; + Button *edit; + VBoxContainer *vbox; + EditorSpinSlider *length; + EditorSpinSlider *page; + HBoxContainer *page_hb; + + void _page_changed(double p_page); + void _length_changed(double p_page); + void _edit_pressed(); + void _property_changed(const String &p_prop, Variant p_value); + void _change_type(Object *p_button, int p_index); + void _change_type_menu(int p_index); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + virtual void update_property(); + EditorPropertyArray(); +}; + +class EditorPropertyDictionary : public EditorProperty { + GDCLASS(EditorPropertyDictionary, EditorProperty) + + PopupMenu *change_type; + bool updating; + + Ref<EditorPropertyDictionaryObject> object; + int page_len; + int page_idx; + int changing_type_idx; + Button *edit; + VBoxContainer *vbox; + EditorSpinSlider *length; + EditorSpinSlider *page; + HBoxContainer *page_hb; + + void _page_changed(double p_page); + void _edit_pressed(); + void _property_changed(const String &p_prop, Variant p_value); + void _change_type(Object *p_button, int p_index); + void _change_type_menu(int p_index); + + void _add_key_value(); + +protected: + static void _bind_methods(); + void _notification(int p_what); + +public: + virtual void update_property(); + EditorPropertyDictionary(); +}; + +#endif // EDITOR_PROPERTIES_ARRAY_DICT_H diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index e7741c7926..297373d299 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -383,11 +383,11 @@ void FileSystemDock::_update_file_display_toggle_button() { if (button_display_mode->is_pressed()) { display_mode = DISPLAY_LIST; button_display_mode->set_icon(get_icon("FileThumbnail", "EditorIcons")); - button_display_mode->set_tooltip(TTR("View items as a grid of thumbnails")); + button_display_mode->set_tooltip(TTR("View items as a grid of thumbnails.")); } else { display_mode = DISPLAY_THUMBNAILS; button_display_mode->set_icon(get_icon("FileList", "EditorIcons")); - button_display_mode->set_tooltip(TTR("View items as a list")); + button_display_mode->set_tooltip(TTR("View items as a list.")); } } @@ -1860,7 +1860,7 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { button_favorite->set_flat(true); button_favorite->set_toggle_mode(true); button_favorite->connect("pressed", this, "_favorites_pressed"); - button_favorite->set_tooltip(TTR("Toggle folder status as Favorite")); + button_favorite->set_tooltip(TTR("Toggle folder status as Favorite.")); button_favorite->set_focus_mode(FOCUS_NONE); toolbar_hbc->add_child(button_favorite); @@ -1916,11 +1916,13 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { file_list_vb->add_child(path_hb); button_tree = memnew(ToolButton); + button_tree->set_tooltip(TTR("Enter tree-view.")); button_tree->hide(); path_hb->add_child(button_tree); search_box = memnew(LineEdit); search_box->set_h_size_flags(SIZE_EXPAND_FILL); + search_box->set_placeholder(TTR("Search files")); search_box->connect("text_changed", this, "_search_changed"); path_hb->add_child(search_box); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 74ea46838b..ddf619866d 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -428,6 +428,7 @@ FindInFilesDialog::FindInFilesDialog() { void FindInFilesDialog::set_search_text(String text) { _search_text_line_edit->set_text(text); + _on_search_text_modified(text); } String FindInFilesDialog::get_search_text() const { diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp index 8443311a54..e42f9780a6 100644 --- a/editor/groups_editor.cpp +++ b/editor/groups_editor.cpp @@ -286,6 +286,9 @@ void GroupDialog::_notification(int p_what) { case NOTIFICATION_ENTER_TREE: { add_button->set_icon(get_icon("Forward", "EditorIcons")); remove_button->set_icon(get_icon("Back", "EditorIcons")); + + add_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + remove_filter->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); } break; } } diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 1d7545f182..2fb3bf7b1e 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -339,7 +339,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Spatial *p_parent) { NodeMap nm; nm.node = node; node_map[p_node->id] = nm; - node_name_map[p_node->name] = p_node->id; + node_name_map[node->get_name()] = p_node->id; Transform xf = p_node->default_transform; xf = collada.fix_transform(xf) * p_node->post_transform; diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp index 128196be5a..f91802b352 100644 --- a/editor/import_dock.cpp +++ b/editor/import_dock.cpp @@ -407,6 +407,7 @@ ImportDock::ImportDock() { set_name("Import"); imported = memnew(Label); imported->add_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_stylebox("normal", "LineEdit")); + imported->set_clip_text(true); add_child(imported); HBoxContainer *hb = memnew(HBoxContainer); add_margin_child(TTR("Import As:"), hb); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp new file mode 100644 index 0000000000..4159a3658e --- /dev/null +++ b/editor/inspector_dock.cpp @@ -0,0 +1,564 @@ +/*************************************************************************/ +/* inspector_dock.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 "inspector_dock.h" + +#include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "editor/plugins/animation_player_editor_plugin.h" + +void InspectorDock::_menu_option(int p_option) { + switch (p_option) { + case RESOURCE_SAVE: { + _save_resource(false); + } break; + case RESOURCE_SAVE_AS: { + _save_resource(true); + } break; + + case OBJECT_REQUEST_HELP: { + if (current) { + editor->set_visible_editor(EditorNode::EDITOR_SCRIPT); + emit_signal("request_help", current->get_class()); + } + } break; + + case OBJECT_COPY_PARAMS: { + editor_data->apply_changes_in_editors(); + if (current) + editor_data->copy_object_params(current); + } break; + + case OBJECT_PASTE_PARAMS: { + editor_data->apply_changes_in_editors(); + if (current) + editor_data->paste_object_params(current); + editor_data->get_undo_redo().clear_history(); + } break; + + case OBJECT_UNIQUE_RESOURCES: { + editor_data->apply_changes_in_editors(); + if (current) { + List<PropertyInfo> props; + current->get_property_list(&props); + Map<RES, RES> duplicates; + for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { + + if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) + continue; + + Variant v = current->get(E->get().name); + if (v.is_ref()) { + REF ref = v; + if (ref.is_valid()) { + + RES res = ref; + if (res.is_valid()) { + + if (!duplicates.has(res)) { + duplicates[res] = res->duplicate(); + } + res = duplicates[res]; + + current->set(E->get().name, res); + } + } + } + } + } + + editor_data->get_undo_redo().clear_history(); + + editor->get_editor_plugins_over()->edit(NULL); + editor->get_editor_plugins_over()->edit(current); + + } break; + + default: { + if (p_option >= OBJECT_METHOD_BASE) { + ERR_FAIL_COND(!current); + + int idx = p_option - OBJECT_METHOD_BASE; + + List<MethodInfo> methods; + current->get_method_list(&methods); + + ERR_FAIL_INDEX(idx, methods.size()); + String name = methods[idx].name; + + if (current) + current->call(name); + } + } + } +} + +void InspectorDock::_new_resource() { + new_resource_dialog->popup_create(true); +} + +void InspectorDock::_load_resource(const String &p_type) { + load_resource_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type(p_type, &extensions); + + load_resource_dialog->clear_filters(); + for (int i = 0; i < extensions.size(); i++) { + load_resource_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + } + + load_resource_dialog->popup_centered_ratio(); +} + +void InspectorDock::_resource_file_selected(String p_file) { + RES res = ResourceLoader::load(p_file); + if (res.is_null()) { + warning_dialog->get_ok()->set_text("Ugh"); + warning_dialog->set_text(TTR("Failed to load resource.")); + return; + }; + + editor->push_item(res.operator->()); +} + +void InspectorDock::_save_resource(bool save_as) const { + uint32_t current = EditorNode::get_singleton()->get_editor_history()->get_current(); + Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) + + RES current_res = RES(Object::cast_to<Resource>(current_obj)); + + if (save_as) + editor->save_resource_as(current_res); + else + editor->save_resource(current_res); +} + +void InspectorDock::_unref_resource() const { + uint32_t current = EditorNode::get_singleton()->get_editor_history()->get_current(); + Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) + + RES current_res = RES(Object::cast_to<Resource>(current_obj)); + current_res->set_path(""); + editor->edit_current(); +} + +void InspectorDock::_copy_resource() const { + uint32_t current = EditorNode::get_singleton()->get_editor_history()->get_current(); + Object *current_obj = current > 0 ? ObjectDB::get_instance(current) : NULL; + + ERR_FAIL_COND(!Object::cast_to<Resource>(current_obj)) + + RES current_res = RES(Object::cast_to<Resource>(current_obj)); + + EditorSettings::get_singleton()->set_resource_clipboard(current_res); +} + +void InspectorDock::_paste_resource() const { + RES r = EditorSettings::get_singleton()->get_resource_clipboard(); + if (r.is_valid()) { + editor->push_item(EditorSettings::get_singleton()->get_resource_clipboard().ptr(), String()); + } +} + +void InspectorDock::_prepare_history() { + EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history(); + + int history_to = MAX(0, editor_history->get_history_len() - 25); + + history_menu->get_popup()->clear(); + + Ref<Texture> base_icon = get_icon("Object", "EditorIcons"); + Set<ObjectID> already; + for (int i = editor_history->get_history_len() - 1; i >= history_to; i--) { + + ObjectID id = editor_history->get_history_obj(i); + Object *obj = ObjectDB::get_instance(id); + if (!obj || already.has(id)) { + if (history_to > 0) { + history_to--; + } + continue; + } + + already.insert(id); + + Ref<Texture> icon = get_icon("Object", "EditorIcons"); + if (has_icon(obj->get_class(), "EditorIcons")) + icon = get_icon(obj->get_class(), "EditorIcons"); + else + icon = base_icon; + + String text; + if (Object::cast_to<Resource>(obj)) { + Resource *r = Object::cast_to<Resource>(obj); + if (r->get_path().is_resource_file()) + text = r->get_path().get_file(); + else if (r->get_name() != String()) { + text = r->get_name(); + } else { + text = r->get_class(); + } + } 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(); + } + + if (i == editor_history->get_history_pos()) { + text = "[" + text + "]"; + } + history_menu->get_popup()->add_icon_item(icon, text, i); + } +} + +void InspectorDock::_select_history(int p_idx) const { + //push it to the top, it is not correct, but it's more useful + ObjectID id = EditorNode::get_singleton()->get_editor_history()->get_history_obj(p_idx); + Object *obj = ObjectDB::get_instance(id); + if (!obj) + return; + editor->push_item(obj); +} + +void InspectorDock::_resource_created() const { + Object *c = new_resource_dialog->instance_selected(); + + ERR_FAIL_COND(!c); + Resource *r = Object::cast_to<Resource>(c); + ERR_FAIL_COND(!r); + + REF res(r); + editor->push_item(c); +} + +void InspectorDock::_resource_selected(const RES &p_res, const String &p_property) const { + if (p_res.is_null()) + return; + + RES r = p_res; + editor->push_item(r.operator->(), p_property); +} + +void InspectorDock::_edit_forward() { + if (EditorNode::get_singleton()->get_editor_history()->next()) + editor->edit_current(); +} +void InspectorDock::_edit_back() { + EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history(); + if (editor_history->previous() || editor_history->get_path_size() == 1) + editor->edit_current(); +} + +void InspectorDock::_menu_collapseall() { + inspector->collapse_all_folding(); +} + +void InspectorDock::_menu_expandall() { + inspector->expand_all_folding(); +} + +void InspectorDock::_property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance) { + AnimationPlayerEditor::singleton->get_key_editor()->insert_value_key(p_keyed, p_value, p_advance); +} + +void InspectorDock::_transform_keyed(Object *sp, const String &p_sub, const Transform &p_key) { + Spatial *s = Object::cast_to<Spatial>(sp); + if (!s) + return; + AnimationPlayerEditor::singleton->get_key_editor()->insert_transform_key(s, p_sub, p_key); +} + +void InspectorDock::_warning_pressed() { + warning_dialog->get_ok()->set_text(TTR("Ok")); + warning_dialog->popup_centered_minsize(); +} + +Container *InspectorDock::get_addon_area() { + return this; +} + +void InspectorDock::_bind_methods() { + ClassDB::bind_method("_menu_option", &InspectorDock::_menu_option); + + ClassDB::bind_method("update_keying", &InspectorDock::update_keying); + ClassDB::bind_method("_property_keyed", &InspectorDock::_property_keyed); + ClassDB::bind_method("_transform_keyed", &InspectorDock::_transform_keyed); + + ClassDB::bind_method("_new_resource", &InspectorDock::_new_resource); + ClassDB::bind_method("_resource_file_selected", &InspectorDock::_resource_file_selected); + ClassDB::bind_method("_open_resource_selector", &InspectorDock::_open_resource_selector); + ClassDB::bind_method("_unref_resource", &InspectorDock::_unref_resource); + ClassDB::bind_method("_paste_resource", &InspectorDock::_paste_resource); + ClassDB::bind_method("_copy_resource", &InspectorDock::_copy_resource); + + ClassDB::bind_method("_select_history", &InspectorDock::_select_history); + ClassDB::bind_method("_prepare_history", &InspectorDock::_prepare_history); + ClassDB::bind_method("_resource_created", &InspectorDock::_resource_created); + ClassDB::bind_method("_resource_selected", &InspectorDock::_resource_selected, DEFVAL("")); + ClassDB::bind_method("_menu_collapseall", &InspectorDock::_menu_collapseall); + ClassDB::bind_method("_menu_expandall", &InspectorDock::_menu_expandall); + ClassDB::bind_method("_warning_pressed", &InspectorDock::_warning_pressed); + ClassDB::bind_method("_edit_forward", &InspectorDock::_edit_forward); + ClassDB::bind_method("_edit_back", &InspectorDock::_edit_back); + + ADD_SIGNAL(MethodInfo("request_help")); +} + +void InspectorDock::edit_resource(const Ref<Resource> &p_resource) { + _resource_selected(p_resource, ""); +} + +void InspectorDock::open_resource(const String &p_type) { + _load_resource(p_type); +} + +void InspectorDock::set_warning(const String &p_message) { + warning->hide(); + if (p_message != String()) { + warning->show(); + warning_dialog->set_text(p_message); + } +} + +void InspectorDock::clear() { +} + +void InspectorDock::update(Object *p_object) { + + EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history(); + backward_button->set_disabled(editor_history->is_at_beginning()); + forward_button->set_disabled(editor_history->is_at_end()); + + history_menu->set_disabled(true); + if (editor_history->get_history_len() > 0) { + history_menu->set_disabled(false); + } + editor_path->update_path(); + + current = p_object; + + if (!p_object) { + object_menu->set_disabled(true); + warning->hide(); + search->set_editable(false); + + return; + } + + bool is_resource = p_object->is_class("Resource"); + bool is_node = p_object->is_class("Node"); + + object_menu->set_disabled(false); + search->set_editable(true); + + PopupMenu *p = object_menu->get_popup(); + + p->clear(); + p->add_shortcut(ED_SHORTCUT("property_editor/expand_all", TTR("Expand all properties")), EXPAND_ALL); + p->add_shortcut(ED_SHORTCUT("property_editor/collapse_all", TTR("Collapse all properties")), COLLAPSE_ALL); + p->add_separator(); + if (is_resource) { + p->add_item(TTR("Save"), RESOURCE_SAVE); + p->add_item(TTR("Save As..."), RESOURCE_SAVE_AS); + p->add_separator(); + } + p->add_shortcut(ED_SHORTCUT("property_editor/copy_params", TTR("Copy Params")), OBJECT_COPY_PARAMS); + p->add_shortcut(ED_SHORTCUT("property_editor/paste_params", TTR("Paste Params")), OBJECT_PASTE_PARAMS); + p->add_separator(); + p->add_shortcut(ED_SHORTCUT("property_editor/paste_resource", TTR("Paste Resource")), RESOURCE_PASTE); + if (is_resource) { + p->add_shortcut(ED_SHORTCUT("property_editor/copy_resource", TTR("Copy Resource")), RESOURCE_COPY); + p->add_shortcut(ED_SHORTCUT("property_editor/unref_resource", TTR("Make Built-In")), RESOURCE_UNREF); + } + + if (is_resource || is_node) { + p->add_separator(); + p->add_shortcut(ED_SHORTCUT("property_editor/make_subresources_unique", TTR("Make Sub-Resources Unique")), OBJECT_UNIQUE_RESOURCES); + p->add_separator(); + p->add_icon_shortcut(get_icon("HelpSearch", "EditorIcons"), ED_SHORTCUT("property_editor/open_help", TTR("Open in Help")), OBJECT_REQUEST_HELP); + } + + List<MethodInfo> methods; + p_object->get_method_list(&methods); + + if (!methods.empty()) { + + bool found = false; + List<MethodInfo>::Element *I = methods.front(); + int i = 0; + while (I) { + + if (I->get().flags & METHOD_FLAG_EDITOR) { + if (!found) { + p->add_separator(); + found = true; + } + p->add_item(I->get().name.capitalize(), OBJECT_METHOD_BASE + i); + } + i++; + I = I->next(); + } + } +} + +void InspectorDock::update_keying() { + bool valid = false; + + if (AnimationPlayerEditor::singleton->get_key_editor()->has_keying()) { + + EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history(); + if (editor_history->get_path_size() >= 1) { + + Object *obj = ObjectDB::get_instance(editor_history->get_path_object(0)); + if (Object::cast_to<Node>(obj)) { + + valid = true; + } + } + } + + inspector->set_keying(valid); +} + +InspectorDock::InspectorDock(EditorNode *p_editor, EditorData &p_editor_data) { + set_name("Inspector"); + set_theme(p_editor->get_gui_base()->get_theme()); + + editor = p_editor; + editor_data = &p_editor_data; + + HBoxContainer *general_options_hb = memnew(HBoxContainer); + add_child(general_options_hb); + + resource_new_button = memnew(ToolButton); + resource_new_button->set_tooltip(TTR("Create a new resource in memory and edit it.")); + resource_new_button->set_icon(get_icon("New", "EditorIcons")); + general_options_hb->add_child(resource_new_button); + resource_new_button->connect("pressed", this, "_new_resource"); + resource_new_button->set_focus_mode(Control::FOCUS_NONE); + + resource_load_button = memnew(ToolButton); + resource_load_button->set_tooltip(TTR("Load an existing resource from disk and edit it.")); + resource_load_button->set_icon(get_icon("Load", "EditorIcons")); + general_options_hb->add_child(resource_load_button); + resource_load_button->connect("pressed", this, "_open_resource_selector"); + resource_load_button->set_focus_mode(Control::FOCUS_NONE); + + general_options_hb->add_spacer(); + + backward_button = memnew(ToolButton); + general_options_hb->add_child(backward_button); + backward_button->set_icon(get_icon("Back", "EditorIcons")); + backward_button->set_flat(true); + backward_button->set_tooltip(TTR("Go to the previous edited object in history.")); + backward_button->set_disabled(true); + backward_button->connect("pressed", this, "_edit_back"); + + forward_button = memnew(ToolButton); + general_options_hb->add_child(forward_button); + forward_button->set_icon(get_icon("Forward", "EditorIcons")); + forward_button->set_flat(true); + forward_button->set_tooltip(TTR("Go to the next edited object in history.")); + forward_button->set_disabled(true); + forward_button->connect("pressed", this, "_edit_forward"); + + history_menu = memnew(MenuButton); + history_menu->set_tooltip(TTR("History of recently edited objects.")); + history_menu->set_icon(get_icon("History", "EditorIcons")); + general_options_hb->add_child(history_menu); + history_menu->connect("about_to_show", this, "_prepare_history"); + history_menu->get_popup()->connect("id_pressed", this, "_select_history"); + + HBoxContainer *node_info_hb = memnew(HBoxContainer); + add_child(node_info_hb); + + editor_path = memnew(EditorPath(editor->get_editor_history())); + editor_path->set_h_size_flags(Control::SIZE_EXPAND_FILL); + node_info_hb->add_child(editor_path); + + object_menu = memnew(MenuButton); + object_menu->set_icon(get_icon("Tools", "EditorIcons")); + node_info_hb->add_child(object_menu); + object_menu->set_tooltip(TTR("Object properties.")); + object_menu->get_popup()->connect("id_pressed", this, "_menu_option"); + + new_resource_dialog = memnew(CreateDialog); + editor->get_gui_base()->add_child(new_resource_dialog); + new_resource_dialog->set_base_type("Resource"); + new_resource_dialog->connect("create", this, "_resource_created"); + + search = memnew(LineEdit); + search->set_h_size_flags(Control::SIZE_EXPAND_FILL); + search->set_placeholder(TTR("Filter properties")); + search->add_icon_override("right_icon", get_icon("Search", "EditorIcons")); + add_child(search); + + warning = memnew(Button); + add_child(warning); + warning->set_text(TTR("Changes may be lost!")); + warning->set_icon(get_icon("NodeWarning", "EditorIcons")); + warning->hide(); + warning->connect("pressed", this, "_warning_pressed"); + + warning_dialog = memnew(AcceptDialog); + editor->get_gui_base()->add_child(warning_dialog); + + load_resource_dialog = memnew(EditorFileDialog); + add_child(load_resource_dialog); + load_resource_dialog->set_current_dir("res://"); + load_resource_dialog->connect("file_selected", this, "_resource_file_selected"); + + inspector = memnew(EditorInspector); + add_child(inspector); + inspector->set_autoclear(true); + inspector->set_show_categories(true); + inspector->set_v_size_flags(Control::SIZE_EXPAND_FILL); + inspector->set_use_doc_hints(true); + inspector->set_hide_script(false); + inspector->set_enable_capitalize_paths(bool(EDITOR_DEF("interface/editor/capitalize_properties", true))); + inspector->set_use_folding(!bool(EDITOR_DEF("interface/editor/disable_inspector_folding", false))); + inspector->register_text_enter(search); + inspector->set_undo_redo(&editor_data->get_undo_redo()); + + inspector->set_use_filter(true); // TODO: check me + + inspector->connect("resource_selected", this, "_resource_selected"); + inspector->connect("property_keyed", this, "_property_keyed"); +} + +InspectorDock::~InspectorDock() { +} diff --git a/editor/inspector_dock.h b/editor/inspector_dock.h new file mode 100644 index 0000000000..688c8beed7 --- /dev/null +++ b/editor/inspector_dock.h @@ -0,0 +1,137 @@ +/*************************************************************************/ +/* inspector_dock.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 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 INSPECTOR_DOCK_H +#define INSPECTOR_DOCK_H + +#include "editor/animation_editor.h" +#include "editor/connections_dialog.h" +#include "editor/create_dialog.h" +#include "editor/editor_data.h" +#include "editor/editor_inspector.h" +#include "editor/editor_path.h" +#include "scene/gui/box_container.h" +#include "scene/gui/button.h" +#include "scene/gui/control.h" +#include "scene/gui/label.h" +#include "scene/gui/popup_menu.h" +#include "scene/gui/tool_button.h" + +class EditorNode; + +class InspectorDock : public VBoxContainer { + + GDCLASS(InspectorDock, VBoxContainer); + + enum MenuOptions { + RESOURCE_NEW, + RESOURCE_LOAD, + RESOURCE_SAVE, + RESOURCE_SAVE_AS, + RESOURCE_UNREF, + RESOURCE_COPY, + RESOURCE_PASTE, + OBJECT_COPY_PARAMS, + OBJECT_PASTE_PARAMS, + OBJECT_UNIQUE_RESOURCES, + OBJECT_REQUEST_HELP, + + COLLAPSE_ALL, + EXPAND_ALL, + + OBJECT_METHOD_BASE = 500 + }; + + EditorNode *editor; + EditorData *editor_data; + + EditorInspector *inspector; + + Object *current; + + ToolButton *backward_button; + ToolButton *forward_button; + + EditorFileDialog *load_resource_dialog; + CreateDialog *new_resource_dialog; + ToolButton *resource_new_button; + ToolButton *resource_load_button; + MenuButton *resource_save_button; + MenuButton *history_menu; + LineEdit *search; + + MenuButton *object_menu; + EditorPath *editor_path; + + Button *warning; + AcceptDialog *warning_dialog; + + void _menu_option(int p_option); + + void _new_resource(); + void _load_resource(const String &p_type = ""); + void _open_resource_selector() { _load_resource(); }; // just used to call from arg-less signal + void _resource_file_selected(String p_file); + void _save_resource(bool save_as) const; + void _unref_resource() const; + void _copy_resource() const; + void _paste_resource() const; + + void _warning_pressed(); + void _resource_created() const; + void _resource_selected(const RES &p_res, const String &p_property = "") const; + void _edit_forward(); + void _edit_back(); + void _menu_collapseall(); + void _menu_expandall(); + void _select_history(int p_idx) const; + void _prepare_history(); + + void _property_keyed(const String &p_keyed, const Variant &p_value, bool p_advance); + void _transform_keyed(Object *sp, const String &p_sub, const Transform &p_key); + +protected: + static void _bind_methods(); + +public: + void update_keying(); + void edit_resource(const Ref<Resource> &p_resource); + void open_resource(const String &p_type); + void clear(); + void set_warning(const String &p_message); + void update(Object *p_object); + Container *get_addon_area(); + EditorInspector *get_inspector() { return inspector; } + + InspectorDock(EditorNode *p_editor, EditorData &p_editor_data); + ~InspectorDock(); +}; + +#endif diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index d21c84eb61..d595d4dd98 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -705,7 +705,18 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt int len = image_data.size(); PoolByteArray::Read r = image_data.read(); - Ref<Image> image = Ref<Image>(memnew(Image(r.ptr(), len))); + Ref<Image> image = Ref<Image>(memnew(Image)); + + uint8_t png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 }; + uint8_t jpg_signature[3] = { 255, 216, 255 }; + + if (r.ptr()) { + if (memcmp(&r[0], &png_signature[0], 8) == 0) { + image->copy_internals_from(Image::_png_mem_loader_func(r.ptr(), len)); + } else if (memcmp(&r[0], &jpg_signature[0], 3) == 0) { + image->copy_internals_from(Image::_jpg_mem_loader_func(r.ptr(), len)); + } + } if (!image->empty()) { switch (image_queue[p_queue_id].image_type) { @@ -750,7 +761,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons ERR_FAIL_COND(!image_queue.has(p_queue_id)); - if (p_status == HTTPRequest::RESULT_SUCCESS) { + if (p_status == HTTPRequest::RESULT_SUCCESS && p_code < HTTPClient::RESPONSE_BAD_REQUEST) { if (p_code != HTTPClient::RESPONSE_NOT_MODIFIED) { for (int i = 0; i < headers.size(); i++) { @@ -781,7 +792,7 @@ void EditorAssetLibrary::_image_request_completed(int p_status, int p_code, cons _image_update(p_code == HTTPClient::RESPONSE_NOT_MODIFIED, true, p_data, p_queue_id); } else { - WARN_PRINTS("Error getting PNG file from URL: " + image_queue[p_queue_id].image_url); + // WARN_PRINTS("Error getting image file from URL: " + image_queue[p_queue_id].image_url); Object *obj = ObjectDB::get_instance(image_queue[p_queue_id].target); if (obj) { obj->call("set_image", image_queue[p_queue_id].image_type, image_queue[p_queue_id].image_index, get_icon("DefaultProjectIcon", "EditorIcons")); diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.cpp b/editor/plugins/collision_polygon_2d_editor_plugin.cpp index b624d69810..672337ba2f 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.cpp +++ b/editor/plugins/collision_polygon_2d_editor_plugin.cpp @@ -42,6 +42,7 @@ void CollisionPolygon2DEditor::_set_node(Node *p_polygon) { CollisionPolygon2DEditor::CollisionPolygon2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; } CollisionPolygon2DEditorPlugin::CollisionPolygon2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index 7c49408c35..49c54ad67d 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -91,7 +91,7 @@ void CurveEditor::set_curve(Ref<Curve> curve) { } Size2 CurveEditor::get_minimum_size() const { - return Vector2(64, 64); + return Vector2(64, 150) * EDSCALE; } void CurveEditor::_notification(int p_what) { @@ -639,7 +639,7 @@ void CurveEditor::_draw() { Ref<Font> font = get_font("font", "Label"); float font_height = font->get_height(); - const Color text_color = get_color("font_color", "Editor"); + Color text_color = get_color("font_color", "Editor"); { // X axis @@ -720,6 +720,7 @@ void CurveEditor::_draw() { // Help text if (_selected_point > 0 && _selected_point + 1 < curve.get_point_count()) { + text_color.a *= 0.4; draw_string(font, Vector2(50, font_height), TTR("Hold Shift to edit tangents individually"), text_color); } } @@ -750,87 +751,28 @@ void CurveEditor::_bind_methods() { //--------------- -CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { - _editor_node = p_node; - - _view = memnew(CurveEditor); - _view->set_custom_minimum_size(Size2(100, 128 * EDSCALE)); - _view->hide(); - - _toggle_button = _editor_node->add_bottom_panel_item(get_name(), _view); - _toggle_button->hide(); - - get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); -} - -CurveEditorPlugin::~CurveEditorPlugin() { -} - -void CurveEditorPlugin::edit(Object *p_object) { - - Ref<Curve> curve_ref; - - if (_current_ref.is_valid()) { - CurveTexture *ct = Object::cast_to<CurveTexture>(*_current_ref); - if (ct) - ct->disconnect(CoreStringNames::get_singleton()->changed, this, "_curve_texture_changed"); - } - - if (p_object) { - Resource *res = Object::cast_to<Resource>(p_object); - ERR_FAIL_COND(res == NULL); - ERR_FAIL_COND(!handles(p_object)); - - _current_ref = Ref<Resource>(Object::cast_to<Resource>(p_object)); - - if (_current_ref.is_valid()) { - Curve *curve = Object::cast_to<Curve>(*_current_ref); - if (curve) - curve_ref = Ref<Curve>(curve); - else { - CurveTexture *ct = Object::cast_to<CurveTexture>(*_current_ref); - if (ct) { - ct->connect(CoreStringNames::get_singleton()->changed, this, "_curve_texture_changed"); - curve_ref = ct->get_curve(); - } - } - } +bool EditorInspectorPluginCurve::can_handle(Object *p_object) { - } else { - _current_ref = Ref<Resource>(); - } - - _view->set_curve(curve_ref); + return Object::cast_to<Curve>(p_object) != NULL; } -bool CurveEditorPlugin::handles(Object *p_object) const { - // Both handled so that we can keep the curve editor open - return Object::cast_to<Curve>(p_object) || Object::cast_to<CurveTexture>(p_object); -} +void EditorInspectorPluginCurve::parse_begin(Object *p_object) { -void CurveEditorPlugin::make_visible(bool p_visible) { - if (p_visible) { - _toggle_button->show(); - _editor_node->make_bottom_panel_item_visible(_view); - } else { - _toggle_button->hide(); - if (_view->is_visible_in_tree()) - _editor_node->hide_bottom_panel(); - } -} + Curve *curve = Object::cast_to<Curve>(p_object); + ERR_FAIL_COND(!curve); + Ref<Curve> c(curve); -void CurveEditorPlugin::_curve_texture_changed() { - // If the curve is shown indirectly as a CurveTexture is edited, - // we need to monitor when the curve property gets assigned - CurveTexture *ct = Object::cast_to<CurveTexture>(*_current_ref); - if (ct) { - _view->set_curve(ct->get_curve()); - } + CurveEditor *editor = memnew(CurveEditor); + editor->set_curve(curve); + add_custom_control(editor); } -void CurveEditorPlugin::_bind_methods() { +CurveEditorPlugin::CurveEditorPlugin(EditorNode *p_node) { + Ref<EditorInspectorPluginCurve> curve_plugin; + curve_plugin.instance(); + EditorInspector::add_inspector_plugin(curve_plugin); - ClassDB::bind_method(D_METHOD("_curve_texture_changed"), &CurveEditorPlugin::_curve_texture_changed); + get_editor_interface()->get_resource_previewer()->add_preview_generator(memnew(CurvePreviewGenerator)); } //----------------------------------- @@ -852,13 +794,13 @@ Ref<Texture> CurvePreviewGenerator::generate(const Ref<Resource> &p_from) { img_ref.instance(); Image &im = **img_ref; - im.create(thumbnail_size, thumbnail_size, 0, Image::FORMAT_RGBA8); + im.create(thumbnail_size, thumbnail_size / 2, 0, Image::FORMAT_RGBA8); im.lock(); Color bg_color(0.1, 0.1, 0.1, 1.0); for (int i = 0; i < thumbnail_size; i++) { - for (int j = 0; j < thumbnail_size; j++) { + for (int j = 0; j < thumbnail_size / 2; j++) { im.set_pixel(i, j, bg_color); } } diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index 97f1ba2fa1..255f359ed2 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -119,28 +119,19 @@ private: float _tangents_length; }; +class EditorInspectorPluginCurve : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginCurve, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); +}; + class CurveEditorPlugin : public EditorPlugin { GDCLASS(CurveEditorPlugin, EditorPlugin) public: CurveEditorPlugin(EditorNode *p_node); - ~CurveEditorPlugin(); String get_name() const { return "Curve"; } - bool has_main_screen() const { return false; } - void edit(Object *p_object); - bool handles(Object *p_object) const; - void make_visible(bool p_visible); - -private: - static void _bind_methods(); - - void _curve_texture_changed(); - -private: - CurveEditor *_view; - Ref<Resource> _current_ref; - EditorNode *_editor_node; - ToolButton *_toggle_button; }; class CurvePreviewGenerator : public EditorResourcePreviewGenerator { diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index e89cb68935..442bd52ea7 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -33,77 +33,70 @@ #include "canvas_item_editor_plugin.h" #include "spatial_editor_plugin.h" -GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { - - editor = p_node; - ramp_editor = memnew(GradientEdit); - - add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, ramp_editor); - - ramp_editor->set_custom_minimum_size(Size2(100, 48)); - ramp_editor->hide(); - ramp_editor->connect("ramp_changed", this, "ramp_changed"); +Size2 GradientEditor::get_minimum_size() const { + return Size2(0, 60) * EDSCALE; } +void GradientEditor::_gradient_changed() { -void GradientEditorPlugin::edit(Object *p_object) { - - Gradient *gradient = Object::cast_to<Gradient>(p_object); - if (!gradient) + if (editing) return; - gradient_ref = Ref<Gradient>(gradient); - ramp_editor->set_points(gradient_ref->get_points()); -} -bool GradientEditorPlugin::handles(Object *p_object) const { + editing = true; + Vector<Gradient::Point> points = gradient->get_points(); + set_points(points); + editing = false; +} - return p_object->is_class("Gradient"); +void GradientEditor::_ramp_changed() { + + editing = true; + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); + undo_redo->create_action("Gradient Edited"); + undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets()); + undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors()); + undo_redo->add_undo_method(gradient.ptr(), "set_offsets", gradient->get_offsets()); + undo_redo->add_undo_method(gradient.ptr(), "set_colors", gradient->get_colors()); + undo_redo->commit_action(); + editing = false; } -void GradientEditorPlugin::make_visible(bool p_visible) { +void GradientEditor::_bind_methods() { - if (p_visible) { - ramp_editor->show(); - } else { - ramp_editor->hide(); - } + ClassDB::bind_method("_gradient_changed", &GradientEditor::_gradient_changed); + ClassDB::bind_method("_ramp_changed", &GradientEditor::_ramp_changed); } -void GradientEditorPlugin::_ramp_changed() { - - if (gradient_ref.is_valid()) { +void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) { + gradient = p_gradient; + connect("ramp_changed", this, "_ramp_changed"); + gradient->connect("changed", this, "_gradient_changed"); + set_points(gradient->get_points()); +} - UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); +GradientEditor::GradientEditor() { + editing = false; +} - //Not sure if I should convert this data to PoolVector - Vector<float> new_offsets = ramp_editor->get_offsets(); - Vector<Color> new_colors = ramp_editor->get_colors(); - Vector<float> old_offsets = gradient_ref->get_offsets(); - Vector<Color> old_colors = gradient_ref->get_colors(); +/////////////////////// - if (old_offsets.size() != new_offsets.size()) - ur->create_action(TTR("Add/Remove Color Ramp Point")); - else - ur->create_action(TTR("Modify Color Ramp"), UndoRedo::MERGE_ENDS); - ur->add_do_method(this, "undo_redo_gradient", new_offsets, new_colors); - ur->add_undo_method(this, "undo_redo_gradient", old_offsets, old_colors); - ur->commit_action(); +bool EditorInspectorPluginGradient::can_handle(Object *p_object) { - //color_ramp_ref->set_points(ramp_editor->get_points()); - } + return Object::cast_to<Gradient>(p_object) != NULL; } -void GradientEditorPlugin::_undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors) { +void EditorInspectorPluginGradient::parse_begin(Object *p_object) { - gradient_ref->set_offsets(offsets); - gradient_ref->set_colors(colors); - ramp_editor->set_points(gradient_ref->get_points()); - ramp_editor->update(); -} + Gradient *gradient = Object::cast_to<Gradient>(p_object); + Ref<Gradient> g(gradient); -GradientEditorPlugin::~GradientEditorPlugin() { + GradientEditor *editor = memnew(GradientEditor); + editor->set_gradient(g); + add_custom_control(editor); } -void GradientEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("ramp_changed"), &GradientEditorPlugin::_ramp_changed); - ClassDB::bind_method(D_METHOD("undo_redo_gradient", "offsets", "colors"), &GradientEditorPlugin::_undo_redo_gradient); +GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { + + Ref<EditorInspectorPluginGradient> plugin; + plugin.instance(); + add_inspector_plugin(plugin); } diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index 52f4c59575..0c878b168f 100644 --- a/editor/plugins/gradient_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -35,28 +35,39 @@ #include "editor/editor_plugin.h" #include "scene/gui/gradient_edit.h" -class GradientEditorPlugin : public EditorPlugin { +class GradientEditor : public GradientEdit { + GDCLASS(GradientEditor, GradientEdit) - GDCLASS(GradientEditorPlugin, EditorPlugin); + bool editing; + Ref<Gradient> gradient; - Ref<Gradient> gradient_ref; - GradientEdit *ramp_editor; - EditorNode *editor; + void _gradient_changed(); + void _ramp_changed(); protected: static void _bind_methods(); - void _ramp_changed(); - void _undo_redo_gradient(const Vector<float> &offsets, const Vector<Color> &colors); + +public: + virtual Size2 get_minimum_size() const; + void set_gradient(const Ref<Gradient> &p_gradient); + GradientEditor(); +}; + +class EditorInspectorPluginGradient : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginGradient, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); +}; + +class GradientEditorPlugin : public EditorPlugin { + + GDCLASS(GradientEditorPlugin, EditorPlugin); public: virtual String get_name() const { return "ColorRamp"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_object); - virtual bool handles(Object *p_object) const; - virtual void make_visible(bool p_visible); GradientEditorPlugin(EditorNode *p_node); - ~GradientEditorPlugin(); }; #endif /* TOOLS_EDITOR_PLUGINS_COLOR_RAMP_EDITOR_PLUGIN_H_ */ diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp index 47d5a73078..ba6452c1d1 100644 --- a/editor/plugins/line_2d_editor_plugin.cpp +++ b/editor/plugins/line_2d_editor_plugin.cpp @@ -64,6 +64,7 @@ void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, con Line2DEditor::Line2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; } Line2DEditorPlugin::Line2DEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp index d1edf1ae10..0332e15b0e 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.cpp +++ b/editor/plugins/navigation_polygon_editor_plugin.cpp @@ -123,6 +123,7 @@ void NavigationPolygonEditor::_create_resource() { NavigationPolygonEditor::NavigationPolygonEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; } NavigationPolygonEditorPlugin::NavigationPolygonEditorPlugin(EditorNode *p_node) : diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index f04e0a801c..ed41e1931e 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -1035,6 +1035,7 @@ Vector2 Polygon2DEditor::snap_point(Vector2 p_target) const { Polygon2DEditor::Polygon2DEditor(EditorNode *p_editor) : AbstractPolygon2DEditor(p_editor) { + node = NULL; snap_step = Vector2(10, 10); use_snap = false; snap_show_grid = false; diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index c0f91455fa..94dcbd8e18 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -1188,7 +1188,7 @@ void ScriptEditor::_notification(int p_what) { case NOTIFICATION_READY: { get_tree()->connect("tree_changed", this, "_tree_changed"); - editor->connect("request_help", this, "_request_help"); + editor->get_inspector_dock()->connect("request_help", this, "_request_help"); editor->connect("request_help_search", this, "_help_search"); editor->connect("request_help_index", this, "_help_index"); } break; @@ -1404,6 +1404,7 @@ void ScriptEditor::_update_members_overview_visibility() { ScriptEditorBase *se = _get_current_editor(); if (!se) { + members_overview_buttons_hbox->set_visible(false); members_overview->set_visible(false); return; } @@ -2681,7 +2682,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { members_overview_vbox->add_child(members_overview_buttons_hbox); members_overview_alphabeta_sort_button = memnew(ToolButton); - members_overview_alphabeta_sort_button->set_tooltip(TTR("Sort alphabetically")); + members_overview_alphabeta_sort_button->set_tooltip(TTR("Toggle alphabetical sorting of the method list.")); members_overview_alphabeta_sort_button->set_toggle_mode(true); members_overview_alphabeta_sort_button->set_pressed(EditorSettings::get_singleton()->get("text_editor/tools/sort_members_outline_alphabetically")); members_overview_alphabeta_sort_button->connect("toggled", this, "_toggle_members_overview_alpha_sort"); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index f4faab69ed..f6d98cb4c7 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -30,7 +30,26 @@ #include "style_box_editor_plugin.h" -void StyleBoxEditor::edit(const Ref<StyleBox> &p_stylebox) { +bool EditorInspectorPluginStyleBox::can_handle(Object *p_object) { + + return Object::cast_to<StyleBox>(p_object) != NULL; +} + +void EditorInspectorPluginStyleBox::parse_begin(Object *p_object) { + + Ref<StyleBox> sb = Ref<StyleBox>(Object::cast_to<StyleBox>(p_object)); + + StyleBoxPreview *preview = memnew(StyleBoxPreview); + preview->edit(sb); + add_custom_control(preview); +} +bool EditorInspectorPluginStyleBox::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) { + return false; //do not want +} +void EditorInspectorPluginStyleBox::parse_end() { +} + +void StyleBoxPreview::edit(const Ref<StyleBox> &p_stylebox) { if (stylebox.is_valid()) stylebox->disconnect("changed", this, "_sb_changed"); @@ -39,71 +58,33 @@ void StyleBoxEditor::edit(const Ref<StyleBox> &p_stylebox) { preview->add_style_override("panel", stylebox); stylebox->connect("changed", this, "_sb_changed"); } + _sb_changed(); } -void StyleBoxEditor::_sb_changed() { +void StyleBoxPreview::_sb_changed() { preview->update(); + if (stylebox.is_valid()) { + Size2 ms = stylebox->get_minimum_size() * 4 / 3; + ms.height = MAX(ms.height, 150 * EDSCALE); + preview->set_custom_minimum_size(ms); + } } -void StyleBoxEditor::_bind_methods() { +void StyleBoxPreview::_bind_methods() { - ClassDB::bind_method("_sb_changed", &StyleBoxEditor::_sb_changed); - //ClassDB::bind_method("_import",&StyleBoxEditor::_import); - //ClassDB::bind_method("_import_accept",&StyleBoxEditor::_import_accept); - //ClassDB::bind_method("_preview_text_changed",&StyleBoxEditor::_preview_text_changed); + ClassDB::bind_method("_sb_changed", &StyleBoxPreview::_sb_changed); } -StyleBoxEditor::StyleBoxEditor() { - - panel = memnew(Panel); - add_child(panel); - panel->set_anchors_and_margins_preset(Control::PRESET_WIDE); - - Label *l = memnew(Label); - l->set_text(TTR("StyleBox Preview:")); - l->set_position(Point2(5, 5)); - panel->add_child(l); +StyleBoxPreview::StyleBoxPreview() { preview = memnew(Panel); - panel->add_child(preview); - preview->set_position(Point2(50, 50)); - preview->set_size(Size2(200, 100)); -} - -void StyleBoxEditorPlugin::edit(Object *p_node) { - - if (Object::cast_to<StyleBox>(p_node)) { - stylebox_editor->edit(Object::cast_to<StyleBox>(p_node)); - stylebox_editor->show(); - } else - stylebox_editor->hide(); -} - -bool StyleBoxEditorPlugin::handles(Object *p_node) const { - - return p_node->is_class("StyleBox"); -} - -void StyleBoxEditorPlugin::make_visible(bool p_visible) { - - if (p_visible) { - button->show(); - EditorNode::get_singleton()->make_bottom_panel_item_visible(stylebox_editor); - - } else { - if (stylebox_editor->is_visible_in_tree()) - EditorNode::get_singleton()->hide_bottom_panel(); - button->hide(); - } + add_margin_child(TTR("Preview:"), preview); } StyleBoxEditorPlugin::StyleBoxEditorPlugin(EditorNode *p_node) { - stylebox_editor = memnew(StyleBoxEditor); - stylebox_editor->set_custom_minimum_size(Size2(0, 250)); - - //p_node->get_viewport()->add_child(stylebox_editor); - button = p_node->add_bottom_panel_item(TTR("StyleBox"), stylebox_editor); - button->hide(); + Ref<EditorInspectorPluginStyleBox> inspector_plugin; + inspector_plugin.instance(); + add_inspector_plugin(inspector_plugin); } diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index 34d8caaeb6..6b0d7e57a8 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -31,18 +31,17 @@ #ifndef STYLE_BOX_EDITOR_PLUGIN_H #define STYLE_BOX_EDITOR_PLUGIN_H +#include "editor/editor_inspector.h" #include "editor/editor_node.h" #include "scene/gui/option_button.h" #include "scene/gui/texture_rect.h" #include "scene/resources/style_box.h" -class StyleBoxEditor : public Control { +class StyleBoxPreview : public VBoxContainer { - GDCLASS(StyleBoxEditor, Control); + GDCLASS(StyleBoxPreview, VBoxContainer); - Panel *panel; Panel *preview; - Ref<StyleBox> stylebox; void _sb_changed(); @@ -53,23 +52,24 @@ protected: public: void edit(const Ref<StyleBox> &p_stylebox); - StyleBoxEditor(); + StyleBoxPreview(); +}; + +class EditorInspectorPluginStyleBox : public EditorInspectorPlugin { + GDCLASS(EditorInspectorPluginStyleBox, EditorInspectorPlugin) +public: + virtual bool can_handle(Object *p_object); + virtual void parse_begin(Object *p_object); + virtual bool parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage); + virtual void parse_end(); }; class StyleBoxEditorPlugin : public EditorPlugin { GDCLASS(StyleBoxEditorPlugin, EditorPlugin); - StyleBoxEditor *stylebox_editor; - EditorNode *editor; - Button *button; - public: virtual String get_name() const { return "StyleBox"; } - bool has_main_screen() const { return false; } - virtual void edit(Object *p_node); - virtual bool handles(Object *p_node) const; - virtual void make_visible(bool p_visible); StyleBoxEditorPlugin(EditorNode *p_node); }; diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 5ba3931689..e4fdd1f251 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -601,6 +601,17 @@ void TextureRegionEditor::apply_rect(const Rect2 &rect) { void TextureRegionEditor::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_PROCESS: { + if (node_sprite) { + if (node_sprite->is_region()) { + + set_process(false); + EditorNode::get_singleton()->make_bottom_panel_item_visible(this); + } + } else { + set_process(false); + } + } break; case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_READY: { zoom_out->set_icon(get_icon("ZoomLess", "EditorIcons")); @@ -640,6 +651,23 @@ void TextureRegionEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_zoom_out"), &TextureRegionEditor::_zoom_out); } +bool TextureRegionEditor::is_stylebox() { + return obj_styleBox.is_valid(); +} + +bool TextureRegionEditor::is_atlas_texture() { + + return atlas_tex.is_valid(); +} + +bool TextureRegionEditor::is_ninepatch() { + return node_ninepatch != NULL; +} + +Sprite *TextureRegionEditor::get_sprite() { + return node_sprite; +} + void TextureRegionEditor::edit(Object *p_obj) { if (node_sprite) node_sprite->remove_change_receptor(this); @@ -670,6 +698,12 @@ void TextureRegionEditor::edit(Object *p_obj) { tile_set = Ref<TileSet>(NULL); } edit_draw->update(); + if (node_sprite && !node_sprite->is_region()) { + set_process(true); + } + if (!p_obj) { + set_process(false); + } } void TextureRegionEditor::_changed_callback(Object *p_changed, const char *p_prop) { @@ -932,8 +966,12 @@ bool TextureRegionEditorPlugin::handles(Object *p_object) const { void TextureRegionEditorPlugin::make_visible(bool p_visible) { if (p_visible) { texture_region_button->show(); - if (texture_region_button->is_pressed()) - region_editor->show(); + if (region_editor->is_stylebox() || region_editor->is_atlas_texture() || region_editor->is_ninepatch() || (region_editor->get_sprite() && region_editor->get_sprite()->is_region())) { + editor->make_bottom_panel_item_visible(region_editor); + } else { + if (texture_region_button->is_pressed()) + region_editor->show(); + } } else { texture_region_button->hide(); region_editor->edit(NULL); @@ -989,10 +1027,10 @@ TextureRegionEditorPlugin::TextureRegionEditorPlugin(EditorNode *p_node) { editor = p_node; region_editor = memnew(TextureRegionEditor(p_node)); - texture_region_button = p_node->add_bottom_panel_item(TTR("Texture Region"), region_editor); + texture_region_button = p_node->add_bottom_panel_item(TTR("TextureRegion"), region_editor); texture_region_button->set_tooltip(TTR("Texture Region Editor")); - region_editor->set_custom_minimum_size(Size2(0, 200)); + region_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE); region_editor->hide(); texture_region_button->hide(); } diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 1244953a3f..eeba1987a6 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -131,6 +131,10 @@ public: void _region_draw(); void _region_input(const Ref<InputEvent> &p_input); void _scroll_changed(float); + bool is_stylebox(); + bool is_atlas_texture(); + bool is_ninepatch(); + Sprite *get_sprite(); void edit(Object *p_obj); TextureRegionEditor(EditorNode *p_editor); diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index 72b3af5a09..b6468111a5 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -133,14 +133,12 @@ void TileMapEditor::_menu_option(int p_option) { return; undo_redo->create_action(TTR("Erase Selection")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { _set_cell(Point2i(j, i), TileMap::INVALID_CELL, false, false, false); } } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); selection_active = false; @@ -200,6 +198,15 @@ void TileMapEditor::set_selected_tile(int p_tile) { } } +void TileMapEditor::_create_set_cell_undo(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose) { + int prev_id = node->get_cell(p_pos.x, p_pos.y); + bool prev_flip_h = node->is_cell_x_flipped(p_pos.x, p_pos.y); + bool prev_flip_v = node->is_cell_y_flipped(p_pos.x, p_pos.y); + bool prev_transpose = node->is_cell_transposed(p_pos.x, p_pos.y); + undo_redo->add_undo_method(node, "set_cellv", Vector2(p_pos.x, p_pos.y), prev_id, prev_flip_h, prev_flip_v, prev_transpose); + undo_redo->add_do_method(node, "set_cellv", Vector2(p_pos.x, p_pos.y), p_value, p_flip_h, p_flip_v, p_transpose); +} + void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose) { ERR_FAIL_COND(!node); @@ -213,6 +220,7 @@ void TileMapEditor::_set_cell(const Point2i &p_pos, int p_value, bool p_flip_h, if (p_value == prev_val && p_flip_h == prev_flip_h && p_flip_v == prev_flip_v && p_transpose == prev_transpose) return; //check that it's actually different + _create_set_cell_undo(p_pos, p_value, p_flip_h, p_flip_v, p_transpose); node->set_cell(p_pos.x, p_pos.y, p_value, p_flip_h, p_flip_v, p_transpose); node->update_bitmask_area(Point2(p_pos)); } @@ -761,7 +769,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { tool = TOOL_PAINTING; undo_redo->create_action(TTR("Paint TileMap")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); } } else if (tool == TOOL_PICKING) { @@ -785,7 +792,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { _set_cell(over_tile, id, flip_h, flip_v, transpose); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); paint_undo.clear(); @@ -797,12 +803,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { undo_redo->create_action(TTR("Line Draw")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (Map<Point2i, CellOp>::Element *E = paint_undo.front(); E; E = E->next()) { _set_cell(E->key(), id, flip_h, flip_v, transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); paint_undo.clear(); @@ -816,14 +820,12 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { if (id != TileMap::INVALID_CELL) { undo_redo->create_action(TTR("Rectangle Paint")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { _set_cell(Point2i(j, i), id, flip_h, flip_v, transpose); } } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); canvas_item_editor->update(); @@ -833,12 +835,10 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 ofs = over_tile - rectangle.position; undo_redo->create_action(TTR("Duplicate")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (List<TileData>::Element *E = copydata.front(); E; E = E->next()) { _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); copydata.clear(); @@ -849,7 +849,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 ofs = over_tile - rectangle.position; undo_redo->create_action(TTR("Move")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); for (int i = rectangle.position.y; i <= rectangle.position.y + rectangle.size.y; i++) { for (int j = rectangle.position.x; j <= rectangle.position.x + rectangle.size.x; j++) { @@ -860,7 +859,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _set_cell(E->get().pos + ofs, E->get().cell, E->get().flip_h, E->get().flip_v, E->get().transpose); } - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); copydata.clear(); @@ -880,7 +878,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { return false; undo_redo->create_action(TTR("Bucket Fill")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); Dictionary op; op["id"] = get_selected_tile(); @@ -890,7 +887,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { _fill_points(points, op); - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); // We want to keep the bucket-tool active @@ -943,7 +939,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { Point2 local = node->world_to_map(xform_inv.xform(mb->get_position())); undo_redo->create_action(TTR("Erase TileMap")); - undo_redo->add_undo_method(node, "set", "tile_data", node->get("tile_data")); if (mb->get_shift()) { #ifdef APPLE_STYLE_KEYS @@ -970,7 +965,6 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) { } else { if (tool == TOOL_ERASING || tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { - undo_redo->add_do_method(node, "set", "tile_data", node->get("tile_data")); undo_redo->commit_action(); if (tool == TOOL_RECTANGLE_ERASE || tool == TOOL_LINE_ERASE) { diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 642870aec0..b344395489 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -174,6 +174,7 @@ class TileMapEditor : public VBoxContainer { void _update_palette(); void _menu_option(int p_option); + void _create_set_cell_undo(const Point2i &p_pos, int p_value, bool p_flip_h, bool p_flip_v, bool p_transpose); void _set_cell(const Point2i &p_pos, int p_value, bool p_flip_h = false, bool p_flip_v = false, bool p_transpose = false); void _canvas_mouse_enter(); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 7d94cad49b..c79cf02062 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -667,7 +667,7 @@ void TileSetEditor::_on_workspace_draw() { if (mask & TileSet::BIND_BOTTOMRIGHT) { workspace->draw_rect(Rect2(anchor + size / 2, size / 2), c); } - } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else { if (mask & TileSet::BIND_TOPLEFT) { workspace->draw_rect(Rect2(anchor, size / 3), c); } @@ -821,7 +821,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { bit = TileSet::BIND_BOTTOMRIGHT; } } - } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else { if (pos.x < size.x / 3) { if (pos.y < size.y / 3) { bit = TileSet::BIND_TOPLEFT; @@ -884,7 +884,7 @@ void TileSetEditor::_on_workspace_input(const Ref<InputEvent> &p_ie) { bit = TileSet::BIND_BOTTOMRIGHT; } } - } else if (tileset->autotile_get_bitmask_mode(get_current_tile()) == TileSet::BITMASK_3X3) { + } else { if (pos.x < size.x / 3) { if (pos.y < size.y / 3) { bit = TileSet::BIND_TOPLEFT; @@ -1849,7 +1849,7 @@ void TileSetEditorHelper::_get_property_list(List<PropertyInfo> *p_list) const { if (selected_tile < 0 || tileset.is_null()) return; - p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3")); + p_list->push_back(PropertyInfo(Variant::INT, "bitmask_mode", PROPERTY_HINT_ENUM, "2x2,3x3 (minimal),3x3")); p_list->push_back(PropertyInfo(Variant::VECTOR2, "layout/tile_size")); p_list->push_back(PropertyInfo(Variant::INT, "layout/spacing", PROPERTY_HINT_RANGE, "0,256,1")); } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 97d3a070ab..0d06b71420 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -199,6 +199,7 @@ private: sp = TTR("Imported Project"); project_name->set_text(sp); + _text_changed(sp); } } @@ -222,6 +223,7 @@ private: } String sp = p.simplify_path(); project_path->set_text(sp); + _path_text_changed(sp); get_ok()->call_deferred("grab_focus"); } @@ -230,6 +232,7 @@ private: String p = p_path; String sp = p.simplify_path(); project_path->set_text(sp); + _path_text_changed(sp); get_ok()->call_deferred("grab_focus"); } @@ -263,7 +266,9 @@ private: if (d->make_dir(project_name->get_text()) == OK) { d->change_dir(project_name->get_text()); - project_path->set_text(d->get_current_dir()); + String dir_str = d->get_current_dir(); + project_path->set_text(dir_str); + _path_text_changed(dir_str); created_folder_path = d->get_current_dir(); create_dir->set_disabled(true); } else { @@ -475,7 +480,9 @@ private: _remove_created_folder(); project_path->clear(); + _path_text_changed(""); project_name->clear(); + _text_changed(""); if (status_rect->get_texture() == get_icon("StatusError", "EditorIcons")) msg->show(); @@ -540,7 +547,9 @@ public: msg->show(); get_ok()->set_disabled(true); } else if (current->has_setting("application/config/name")) { - project_name->set_text(current->get("application/config/name")); + String proj = current->get("application/config/name"); + project_name->set_text(proj); + _text_changed(proj); } project_name->call_deferred("grab_focus"); @@ -559,7 +568,9 @@ public: fdialog->set_current_dir(d->get_current_dir()); memdelete(d); } - project_name->set_text(TTR("New Game Project")); + String proj = TTR("New Game Project"); + project_name->set_text(proj); + _text_changed(proj); project_path->set_editable(true); browse->set_disabled(false); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 08338b0b2d..b82a036130 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -1936,6 +1936,12 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->add_icon_shortcut(get_icon("ScriptCreate", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/attach_script"), TOOL_ATTACH_SCRIPT); menu->add_icon_shortcut(get_icon("ScriptRemove", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/clear_script"), TOOL_CLEAR_SCRIPT); } + + if (selection.size() > 1) { + //this is not a commonly used action, it makes no sense for it to be where it was nor always present. + menu->add_separator(); + menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); + } menu->add_separator(); menu->add_icon_shortcut(get_icon("Remove", "EditorIcons"), ED_SHORTCUT("scene_tree/delete", TTR("Delete Node(s)"), KEY_DELETE), TOOL_ERASE); menu->set_size(Size2(1, 1)); diff --git a/main/main.cpp b/main/main.cpp index c287bc81cb..70713e2dd8 100644 --- a/main/main.cpp +++ b/main/main.cpp @@ -1444,7 +1444,7 @@ bool Main::start() { } #endif - if (!project_manager) { // game or editor + if (!project_manager && !editor) { // game if (game_path != "" || script != "") { //autoload List<PropertyInfo> props; @@ -1465,24 +1465,13 @@ bool Main::start() { if (global_var) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { -#ifdef TOOLS_ENABLED - if (editor) { - ScriptServer::get_language(i)->add_named_global_constant(name, Variant()); - } else { - ScriptServer::get_language(i)->add_global_constant(name, Variant()); - } -#else ScriptServer::get_language(i)->add_global_constant(name, Variant()); -#endif } } } //second pass, load into global constants List<Node *> to_add; -#ifdef TOOLS_ENABLED - ResourceLoader::set_timestamp_on_load(editor); // Avoid problems when editing -#endif for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) { String s = E->get().name; @@ -1528,23 +1517,11 @@ bool Main::start() { if (global_var) { for (int i = 0; i < ScriptServer::get_language_count(); i++) { -#ifdef TOOLS_ENABLED - if (editor) { - ScriptServer::get_language(i)->add_named_global_constant(name, n); - } else { - ScriptServer::get_language(i)->add_global_constant(name, n); - } -#else ScriptServer::get_language(i)->add_global_constant(name, n); -#endif } } } -#ifdef TOOLS_ENABLED - ResourceLoader::set_timestamp_on_load(false); -#endif - for (List<Node *>::Element *E = to_add.front(); E; E = E->next()) { sml->get_root()->add_child(E->get()); diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 9947512444..5c834966c5 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -738,6 +738,9 @@ int GDScriptCompiler::_parse_expression(CodeGen &codegen, const GDScriptParser:: case GDScriptParser::OperatorNode::OP_NEG: { if (!_create_unary_operator(codegen, on, Variant::OP_NEGATE, p_stack_level)) return -1; } break; + case GDScriptParser::OperatorNode::OP_POS: { + if (!_create_unary_operator(codegen, on, Variant::OP_POSITIVE, p_stack_level)) return -1; + } break; case GDScriptParser::OperatorNode::OP_NOT: { if (!_create_unary_operator(codegen, on, Variant::OP_NOT, p_stack_level)) return -1; } break; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 30ef167466..4286412c14 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -416,7 +416,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na s += p_args[i].get_slice(":", 0); } } - s += "):\n" + _get_indentation() + "pass # replace with function body\n"; + s += "):\n" + _get_indentation() + "pass # Replace with function body.\n"; return s; } diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp index fd51a20d15..24292b77ed 100644 --- a/modules/mono/csharp_script.cpp +++ b/modules/mono/csharp_script.cpp @@ -446,7 +446,7 @@ String CSharpLanguage::make_function(const String &p_class, const String &p_name s += variant_type_to_managed_name(arg.get_slice(":", 1)) + " " + escape_csharp_keyword(arg.get_slice(":", 0)); } - s += ")\n{\n // Replace with function body\n}\n"; + s += ")\n{\n // Replace with function body.\n}\n"; return s; #else diff --git a/modules/mono/glue/cs_files/Basis.cs b/modules/mono/glue/cs_files/Basis.cs index 929b13d70c..270f3b80a2 100644 --- a/modules/mono/glue/cs_files/Basis.cs +++ b/modules/mono/glue/cs_files/Basis.cs @@ -446,6 +446,26 @@ namespace Godot _z = new Vector3(xz - wy, yz + wx, 1.0f - (xx + yy)); } + public Basis(Vector3 euler) + { + real_t c; + real_t s; + + c = Mathf.Cos(euler.x); + s = Mathf.Sin(euler.x); + var xmat = new Basis((real_t)1.0, (real_t)0.0, (real_t)0.0, (real_t)0.0, c, -s, (real_t)0.0, s, c); + + c = Mathf.Cos(euler.y); + s = Mathf.Sin(euler.y); + var ymat = new Basis(c, (real_t)0.0, s, (real_t)0.0, (real_t)1.0, (real_t)0.0, -s, (real_t)0.0, c); + + c = Mathf.Cos(euler.z); + s = Mathf.Sin(euler.z); + var zmat = new Basis(c, -s, (real_t)0.0, s, c, (real_t)0.0, (real_t)0.0, (real_t)0.0, (real_t)1.0); + + this = ymat * xmat * zmat; + } + public Basis(Vector3 axis, real_t phi) { var axis_sq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z); diff --git a/modules/mono/glue/cs_files/Color.cs b/modules/mono/glue/cs_files/Color.cs index af94bb616e..e0d6d27840 100644 --- a/modules/mono/glue/cs_files/Color.cs +++ b/modules/mono/glue/cs_files/Color.cs @@ -249,6 +249,15 @@ namespace Godot ); } + public Color Darkened(float amount) + { + Color res = this; + res.r = res.r * (1.0f - amount); + res.g = res.g * (1.0f - amount); + res.b = res.b * (1.0f - amount); + return res; + } + public float Gray() { return (r + g + b) / 3.0f; @@ -263,6 +272,15 @@ namespace Godot ); } + public Color Lightened(float amount) + { + Color res = this; + res.r = res.r + (1.0f - res.r) * amount; + res.g = res.g + (1.0f - res.g) * amount; + res.b = res.b + (1.0f - res.b) * amount; + return res; + } + public Color LinearInterpolate(Color c, float t) { var res = this; @@ -275,15 +293,15 @@ namespace Godot return res; } - public int To32() + public int ToRgba32() { - int c = (byte)(a * 255); - c <<= 8; - c |= (byte)(r * 255); + int c = (byte)(r * 255); c <<= 8; c |= (byte)(g * 255); c <<= 8; c |= (byte)(b * 255); + c <<= 8; + c |= (byte)(a * 255); return c; } diff --git a/modules/mono/glue/cs_files/Plane.cs b/modules/mono/glue/cs_files/Plane.cs index 8b92522029..1020f06bf5 100644 --- a/modules/mono/glue/cs_files/Plane.cs +++ b/modules/mono/glue/cs_files/Plane.cs @@ -9,17 +9,23 @@ namespace Godot { public struct Plane : IEquatable<Plane> { - Vector3 normal; + private Vector3 _normal; + + public Vector3 Normal + { + get { return _normal; } + set { _normal = value; } + } public real_t x { get { - return normal.x; + return _normal.x; } set { - normal.x = value; + _normal.x = value; } } @@ -27,11 +33,11 @@ namespace Godot { get { - return normal.y; + return _normal.y; } set { - normal.y = value; + _normal.y = value; } } @@ -39,62 +45,62 @@ namespace Godot { get { - return normal.z; + return _normal.z; } set { - normal.z = value; + _normal.z = value; } } - real_t d; + public real_t D { get; set; } public Vector3 Center { get { - return normal * d; + return _normal * D; } } public real_t DistanceTo(Vector3 point) { - return normal.Dot(point) - d; + return _normal.Dot(point) - D; } public Vector3 GetAnyPoint() { - return normal * d; + return _normal * D; } public bool HasPoint(Vector3 point, real_t epsilon = Mathf.Epsilon) { - real_t dist = normal.Dot(point) - d; + real_t dist = _normal.Dot(point) - D; return Mathf.Abs(dist) <= epsilon; } public Vector3 Intersect3(Plane b, Plane c) { - real_t denom = normal.Cross(b.normal).Dot(c.normal); + real_t denom = _normal.Cross(b._normal).Dot(c._normal); if (Mathf.Abs(denom) <= Mathf.Epsilon) return new Vector3(); - Vector3 result = b.normal.Cross(c.normal) * d + - c.normal.Cross(normal) * b.d + - normal.Cross(b.normal) * c.d; + Vector3 result = b._normal.Cross(c._normal) * D + + c._normal.Cross(_normal) * b.D + + _normal.Cross(b._normal) * c.D; return result / denom; } public Vector3 IntersectRay(Vector3 from, Vector3 dir) { - real_t den = normal.Dot(dir); + real_t den = _normal.Dot(dir); if (Mathf.Abs(den) <= Mathf.Epsilon) return new Vector3(); - real_t dist = (normal.Dot(from) - d) / den; + real_t dist = (_normal.Dot(from) - D) / den; // This is a ray, before the emitting pos (from) does not exist if (dist > Mathf.Epsilon) @@ -106,12 +112,12 @@ namespace Godot public Vector3 IntersectSegment(Vector3 begin, Vector3 end) { Vector3 segment = begin - end; - real_t den = normal.Dot(segment); + real_t den = _normal.Dot(segment); if (Mathf.Abs(den) <= Mathf.Epsilon) return new Vector3(); - real_t dist = (normal.Dot(begin) - d) / den; + real_t dist = (_normal.Dot(begin) - D) / den; if (dist < -Mathf.Epsilon || dist > 1.0f + Mathf.Epsilon) return new Vector3(); @@ -121,46 +127,46 @@ namespace Godot public bool IsPointOver(Vector3 point) { - return normal.Dot(point) > d; + return _normal.Dot(point) > D; } public Plane Normalized() { - real_t len = normal.Length(); + real_t len = _normal.Length(); if (len == 0) return new Plane(0, 0, 0, 0); - return new Plane(normal / len, d / len); + return new Plane(_normal / len, D / len); } public Vector3 Project(Vector3 point) { - return point - normal * DistanceTo(point); + return point - _normal * DistanceTo(point); } // Constructors public Plane(real_t a, real_t b, real_t c, real_t d) { - normal = new Vector3(a, b, c); - this.d = d; + _normal = new Vector3(a, b, c); + this.D = d; } public Plane(Vector3 normal, real_t d) { - this.normal = normal; - this.d = d; + this._normal = normal; + this.D = d; } public Plane(Vector3 v1, Vector3 v2, Vector3 v3) { - normal = (v1 - v3).Cross(v1 - v2); - normal.Normalize(); - d = normal.Dot(v1); + _normal = (v1 - v3).Cross(v1 - v2); + _normal.Normalize(); + D = _normal.Dot(v1); } public static Plane operator -(Plane plane) { - return new Plane(-plane.normal, -plane.d); + return new Plane(-plane._normal, -plane.D); } public static bool operator ==(Plane left, Plane right) @@ -185,20 +191,20 @@ namespace Godot public bool Equals(Plane other) { - return normal == other.normal && d == other.d; + return _normal == other._normal && D == other.D; } public override int GetHashCode() { - return normal.GetHashCode() ^ d.GetHashCode(); + return _normal.GetHashCode() ^ D.GetHashCode(); } public override string ToString() { return String.Format("({0}, {1})", new object[] { - normal.ToString(), - d.ToString() + _normal.ToString(), + D.ToString() }); } @@ -206,8 +212,8 @@ namespace Godot { return String.Format("({0}, {1})", new object[] { - normal.ToString(format), - d.ToString(format) + _normal.ToString(format), + D.ToString(format) }); } } diff --git a/modules/mono/glue/cs_files/StringExtensions.cs b/modules/mono/glue/cs_files/StringExtensions.cs index 21090fb68d..eaeed7b37b 100644 --- a/modules/mono/glue/cs_files/StringExtensions.cs +++ b/modules/mono/glue/cs_files/StringExtensions.cs @@ -225,7 +225,7 @@ namespace Godot if (pos < 0) return instance; - return instance.Substring(pos + 1, instance.Length); + return instance.Substring(pos + 1); } // <summary> diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h index c1022a1aca..2b2d21553b 100644 --- a/platform/osx/os_osx.h +++ b/platform/osx/os_osx.h @@ -109,6 +109,7 @@ public: bool minimized; bool maximized; bool zoomed; + bool resizable; Size2 window_size; Rect2 restore_rect; diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm index bde0b4e898..5589f93a5d 100644 --- a/platform/osx/os_osx.mm +++ b/platform/osx/os_osx.mm @@ -913,7 +913,7 @@ static int remapKey(unsigned int key) { CFDataRef layoutData = (CFDataRef)TISGetInputSourceProperty(currentKeyboard, kTISPropertyUnicodeKeyLayoutData); if (!layoutData) - return nil; + return 0; const UCKeyboardLayout *keyboardLayout = (const UCKeyboardLayout *)CFDataGetBytePtr(layoutData); @@ -1184,6 +1184,7 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a if (p_desired.borderless_window) { styleMask = NSWindowStyleMaskBorderless; } else { + resizable = p_desired.resizable; styleMask = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (p_desired.resizable ? NSWindowStyleMaskResizable : 0); } @@ -1480,7 +1481,7 @@ void OS_OSX::set_cursor_shape(CursorShape p_shape) { if (cursor_shape == p_shape) return; - if (mouse_mode != MOUSE_MODE_VISIBLE) { + if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { cursor_shape = p_shape; return; } @@ -1740,7 +1741,8 @@ String OS_OSX::get_godot_dir_name() const { String OS_OSX::get_system_dir(SystemDir p_dir) const { - NSSearchPathDirectory id = 0; + NSSearchPathDirectory id; + bool found = true; switch (p_dir) { case SYSTEM_DIR_DESKTOP: { @@ -1761,10 +1763,13 @@ String OS_OSX::get_system_dir(SystemDir p_dir) const { case SYSTEM_DIR_PICTURES: { id = NSPicturesDirectory; } break; + default: { + found = false; + } } String ret; - if (id) { + if (found) { NSArray *paths = NSSearchPathForDirectoriesInDomains(id, NSUserDomainMask, YES); if (paths && [paths count] >= 1) { @@ -2110,6 +2115,8 @@ void OS_OSX::set_window_resizable(bool p_enabled) { [window_object setStyleMask:[window_object styleMask] | NSWindowStyleMaskResizable]; else [window_object setStyleMask:[window_object styleMask] & ~NSWindowStyleMaskResizable]; + + resizable = p_enabled; }; bool OS_OSX::is_window_resizable() const { @@ -2219,7 +2226,7 @@ void OS_OSX::set_borderless_window(bool p_borderless) { if (layered_window) set_window_per_pixel_transparency_enabled(false); - [window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable]; + [window_object setStyleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | (resizable ? NSWindowStyleMaskResizable : 0)]; // Force update of the window styles NSRect frameRect = [window_object frame]; @@ -2615,6 +2622,7 @@ OS_OSX::OS_OSX() { minimized = false; window_size = Vector2(1024, 600); zoomed = false; + resizable = false; Vector<Logger *> loggers; loggers.push_back(memnew(OSXTerminalLogger)); diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp index d6cdea7b88..8d664b5832 100644 --- a/platform/windows/os_windows.cpp +++ b/platform/windows/os_windows.cpp @@ -623,9 +623,12 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) case WM_SIZE: { int window_w = LOWORD(lParam); int window_h = HIWORD(lParam); - if (window_w > 0 && window_h > 0) { + if (window_w > 0 && window_h > 0 && !preserve_window_size) { video_mode.width = window_w; video_mode.height = window_h; + } else { + preserve_window_size = false; + set_window_size(Size2(video_mode.width, video_mode.height)); } if (wParam == SIZE_MAXIMIZED) { maximized = true; @@ -777,7 +780,9 @@ LRESULT OS_Windows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) SetCursor(NULL); } else { if (hCursor != NULL) { - SetCursor(hCursor); + CursorShape c = cursor_shape; + cursor_shape = CURSOR_MAX; + set_cursor_shape(c); hCursor = NULL; } } @@ -1561,6 +1566,15 @@ void OS_Windows::set_window_size(const Size2 p_size) { } MoveWindow(hWnd, rect.left, rect.top, w, h, TRUE); + + // Don't let the mouse leave the window when resizing to a smaller resolution + if (mouse_mode == MOUSE_MODE_CONFINED) { + RECT rect; + GetClientRect(hWnd, &rect); + ClientToScreen(hWnd, (POINT *)&rect.left); + ClientToScreen(hWnd, (POINT *)&rect.right); + ClipCursor(&rect); + } } void OS_Windows::set_window_fullscreen(bool p_enabled) { @@ -1767,6 +1781,7 @@ void OS_Windows::set_borderless_window(bool p_borderless) { video_mode.borderless_window = p_borderless; + preserve_window_size = true; _update_window_style(); } @@ -1785,7 +1800,7 @@ void OS_Windows::_update_window_style(bool repaint) { } } - SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); + SetWindowPos(hWnd, video_mode.always_on_top ? HWND_TOPMOST : HWND_NOTOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE); if (repaint) { RECT rect; @@ -1996,7 +2011,7 @@ void OS_Windows::set_cursor_shape(CursorShape p_shape) { if (cursor_shape == p_shape) return; - if (mouse_mode != MOUSE_MODE_VISIBLE) { + if (mouse_mode != MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { cursor_shape = p_shape; return; } diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h index 221109318e..81849497ee 100644 --- a/platform/windows/os_windows.h +++ b/platform/windows/os_windows.h @@ -105,6 +105,7 @@ class OS_Windows : public OS { Size2 window_rect; VideoMode video_mode; + bool preserve_window_size = false; MainLoop *main_loop; diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp index eec371865e..7b514d0f90 100644 --- a/platform/x11/os_x11.cpp +++ b/platform/x11/os_x11.cpp @@ -1292,6 +1292,9 @@ void OS_X11::set_borderless_window(bool p_borderless) { hints.decorations = current_videomode.borderless_window ? 0 : 1; property = XInternAtom(x11_display, "_MOTIF_WM_HINTS", True); XChangeProperty(x11_display, x11_window, property, property, 32, PropModeReplace, (unsigned char *)&hints, 5); + + // Preserve window size + set_window_size(Size2(current_videomode.width, current_videomode.height)); } bool OS_X11::get_borderless_window() { @@ -2407,7 +2410,7 @@ void OS_X11::set_cursor_shape(CursorShape p_shape) { if (p_shape == current_cursor) return; - if (mouse_mode == MOUSE_MODE_VISIBLE) { + if (mouse_mode == MOUSE_MODE_VISIBLE && mouse_mode != MOUSE_MODE_CONFINED) { if (cursors[p_shape] != None) XDefineCursor(x11_display, x11_window, cursors[p_shape]); else if (cursors[CURSOR_ARROW] != None) diff --git a/scene/2d/navigation2d.cpp b/scene/2d/navigation2d.cpp index 4737e14111..16e0386952 100644 --- a/scene/2d/navigation2d.cpp +++ b/scene/2d/navigation2d.cpp @@ -671,7 +671,7 @@ Object *Navigation2D::get_closest_point_owner(const Vector2 &p_point) { if (Geometry::is_point_in_triangle(p_point, _get_vertex(p.edges[0].point), _get_vertex(p.edges[i - 1].point), _get_vertex(p.edges[i].point))) { - E->get().owner; + return E->get().owner; } } } diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp index 5294189c65..d88e148b2c 100644 --- a/scene/2d/tile_map.cpp +++ b/scene/2d/tile_map.cpp @@ -845,16 +845,37 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { mask |= TileSet::BIND_BOTTOMRIGHT; } - } else if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3) { - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) { - mask |= TileSet::BIND_TOPLEFT; + } else { + if (tile_set->autotile_get_bitmask_mode(id) == TileSet::BITMASK_3X3_MINIMAL) { + if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { + mask |= TileSet::BIND_TOPLEFT; + } + if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { + mask |= TileSet::BIND_TOPRIGHT; + } + if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { + mask |= TileSet::BIND_BOTTOMLEFT; + } + if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1)) && tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { + mask |= TileSet::BIND_BOTTOMRIGHT; + } + } else { + if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y - 1))) { + mask |= TileSet::BIND_TOPLEFT; + } + if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) { + mask |= TileSet::BIND_TOPRIGHT; + } + if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) { + mask |= TileSet::BIND_BOTTOMLEFT; + } + if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) { + mask |= TileSet::BIND_BOTTOMRIGHT; + } } if (tile_set->is_tile_bound(id, get_cell(p_x, p_y - 1))) { mask |= TileSet::BIND_TOP; } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y - 1))) { - mask |= TileSet::BIND_TOPRIGHT; - } if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y))) { mask |= TileSet::BIND_LEFT; } @@ -862,15 +883,9 @@ void TileMap::update_cell_bitmask(int p_x, int p_y) { if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y))) { mask |= TileSet::BIND_RIGHT; } - if (tile_set->is_tile_bound(id, get_cell(p_x - 1, p_y + 1))) { - mask |= TileSet::BIND_BOTTOMLEFT; - } if (tile_set->is_tile_bound(id, get_cell(p_x, p_y + 1))) { mask |= TileSet::BIND_BOTTOM; } - if (tile_set->is_tile_bound(id, get_cell(p_x + 1, p_y + 1))) { - mask |= TileSet::BIND_BOTTOMRIGHT; - } } Vector2 coord = tile_set->autotile_get_subtile_for_bitmask(id, mask, this, Vector2(p_x, p_y)); E->get().autotile_coord_x = (int)coord.x; diff --git a/scene/3d/scenario_fx.cpp b/scene/3d/scenario_fx.cpp index d5bff676cb..26cbfc0b11 100644 --- a/scene/3d/scenario_fx.cpp +++ b/scene/3d/scenario_fx.cpp @@ -93,9 +93,10 @@ String WorldEnvironment::get_configuration_warning() const { return TTR("Only one WorldEnvironment is allowed per scene (or set of instanced scenes)."); } - if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) { - return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes)."); - } + // Commenting this warning for now, I think it makes no sense. If anyone can figure out what its supposed to do, feedback welcome. Else it should be deprecated. + //if (environment.is_valid() && get_viewport() && !get_viewport()->get_camera() && environment->get_background() != Environment::BG_CANVAS) { + // return TTR("This WorldEnvironment is ignored. Either add a Camera (for 3D scenes) or set this environment's Background Mode to Canvas (for 2D scenes)."); + //} return String(); } diff --git a/scene/gui/container.cpp b/scene/gui/container.cpp index 177582c87c..7df03bf7c6 100644 --- a/scene/gui/container.cpp +++ b/scene/gui/container.cpp @@ -51,6 +51,8 @@ void Container::add_child_notify(Node *p_child) { control->connect("size_flags_changed", this, "queue_sort"); control->connect("minimum_size_changed", this, "_child_minsize_changed"); control->connect("visibility_changed", this, "_child_minsize_changed"); + + minimum_size_changed(); queue_sort(); } @@ -61,6 +63,7 @@ void Container::move_child_notify(Node *p_child) { if (!Object::cast_to<Control>(p_child)) return; + minimum_size_changed(); queue_sort(); } @@ -75,6 +78,8 @@ void Container::remove_child_notify(Node *p_child) { control->disconnect("size_flags_changed", this, "queue_sort"); control->disconnect("minimum_size_changed", this, "_child_minsize_changed"); control->disconnect("visibility_changed", this, "_child_minsize_changed"); + + minimum_size_changed(); queue_sort(); } diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp index 3097ecaf16..d07b5a9f65 100644 --- a/scene/gui/control.cpp +++ b/scene/gui/control.cpp @@ -277,6 +277,7 @@ void Control::_update_minimum_size() { data.updating_last_minimum_size = false; if (minsize != data.last_minimum_size) { + data.last_minimum_size = minsize; emit_signal(SceneStringNames::get_singleton()->minimum_size_changed); } } diff --git a/scene/gui/gradient_edit.cpp b/scene/gui/gradient_edit.cpp index 9fc8e98a7f..b5622604e2 100644 --- a/scene/gui/gradient_edit.cpp +++ b/scene/gui/gradient_edit.cpp @@ -147,6 +147,7 @@ void GradientEdit::_gui_input(const Ref<InputEvent> &p_event) { grabbed = _get_point_from_pos(x); //grab or select if (grabbed != -1) { + grabbed = false; return; } diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index e57af0a4c0..2b644e7f96 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -1005,7 +1005,6 @@ void LineEdit::set_text(String p_text) { update(); cursor_pos = 0; window_pos = 0; - _text_changed(); } void LineEdit::clear() { diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp index fd2466407e..93865cebde 100644 --- a/scene/gui/popup_menu.cpp +++ b/scene/gui/popup_menu.cpp @@ -533,6 +533,7 @@ void PopupMenu::add_icon_item(const Ref<Texture> &p_icon, const String &p_label, item.ID = p_ID; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) { @@ -543,6 +544,7 @@ void PopupMenu::add_item(const String &p_label, int p_ID, uint32_t p_accel) { item.ID = p_ID; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, int p_ID) { @@ -554,6 +556,7 @@ void PopupMenu::add_submenu_item(const String &p_label, const String &p_submenu, item.submenu = p_submenu; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { @@ -567,6 +570,7 @@ void PopupMenu::add_icon_check_item(const Ref<Texture> &p_icon, const String &p_ item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel) { @@ -579,6 +583,7 @@ void PopupMenu::add_check_item(const String &p_label, int p_ID, uint32_t p_accel item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p_accel) { @@ -586,6 +591,7 @@ void PopupMenu::add_radio_check_item(const String &p_label, int p_ID, uint32_t p add_check_item(p_label, p_ID, p_accel); items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); + minimum_size_changed(); } void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const String &p_label, int p_ID, uint32_t p_accel) { @@ -593,6 +599,7 @@ void PopupMenu::add_icon_radio_check_item(const Ref<Texture> &p_icon, const Stri add_icon_check_item(p_icon, p_label, p_ID, p_accel); items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); + minimum_size_changed(); } void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { @@ -608,6 +615,7 @@ void PopupMenu::add_icon_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut item.shortcut_is_global = p_global; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { @@ -622,6 +630,7 @@ void PopupMenu::add_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_g item.shortcut_is_global = p_global; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { @@ -638,6 +647,7 @@ void PopupMenu::add_icon_check_shortcut(const Ref<Texture> &p_icon, const Ref<Sh item.shortcut_is_global = p_global; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { @@ -653,6 +663,7 @@ void PopupMenu::add_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bo item.checkable_type = Item::CHECKABLE_TYPE_CHECK_BOX; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ID, bool p_global) { @@ -660,6 +671,7 @@ void PopupMenu::add_radio_check_shortcut(const Ref<ShortCut> &p_shortcut, int p_ add_check_shortcut(p_shortcut, p_ID, p_global); items[items.size() - 1].checkable_type = Item::CHECKABLE_TYPE_RADIO_BUTTON; update(); + minimum_size_changed(); } void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int p_default_state, int p_ID, uint32_t p_accel) { @@ -673,6 +685,7 @@ void PopupMenu::add_multistate_item(const String &p_label, int p_max_states, int item.state = p_default_state; items.push_back(item); update(); + minimum_size_changed(); } void PopupMenu::set_item_text(int p_idx, const String &p_text) { @@ -682,6 +695,7 @@ void PopupMenu::set_item_text(int p_idx, const String &p_text) { items[p_idx].xl_text = tr(p_text); update(); + minimum_size_changed(); } void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { @@ -689,6 +703,7 @@ void PopupMenu::set_item_icon(int p_idx, const Ref<Texture> &p_icon) { items[p_idx].icon = p_icon; update(); + minimum_size_changed(); } void PopupMenu::set_item_checked(int p_idx, bool p_checked) { @@ -697,6 +712,7 @@ void PopupMenu::set_item_checked(int p_idx, bool p_checked) { items[p_idx].checked = p_checked; update(); + minimum_size_changed(); } void PopupMenu::set_item_id(int p_idx, int p_ID) { @@ -704,6 +720,7 @@ void PopupMenu::set_item_id(int p_idx, int p_ID) { items[p_idx].ID = p_ID; update(); + minimum_size_changed(); } void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { @@ -712,6 +729,7 @@ void PopupMenu::set_item_accelerator(int p_idx, uint32_t p_accel) { items[p_idx].accel = p_accel; update(); + minimum_size_changed(); } void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { @@ -719,6 +737,7 @@ void PopupMenu::set_item_metadata(int p_idx, const Variant &p_meta) { ERR_FAIL_INDEX(p_idx, items.size()); items[p_idx].metadata = p_meta; update(); + minimum_size_changed(); } void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { @@ -726,6 +745,7 @@ void PopupMenu::set_item_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, items.size()); items[p_idx].disabled = p_disabled; update(); + minimum_size_changed(); } void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { @@ -733,6 +753,7 @@ void PopupMenu::set_item_submenu(int p_idx, const String &p_submenu) { ERR_FAIL_INDEX(p_idx, items.size()); items[p_idx].submenu = p_submenu; update(); + minimum_size_changed(); } void PopupMenu::toggle_item_checked(int p_idx) { @@ -740,6 +761,7 @@ void PopupMenu::toggle_item_checked(int p_idx) { ERR_FAIL_INDEX(p_idx, items.size()); items[p_idx].checked = !items[p_idx].checked; update(); + minimum_size_changed(); } String PopupMenu::get_item_text(int p_idx) const { @@ -881,6 +903,7 @@ void PopupMenu::set_item_h_offset(int p_idx, int p_offset) { ERR_FAIL_INDEX(p_idx, items.size()); items[p_idx].h_ofs = p_offset; update(); + minimum_size_changed(); } void PopupMenu::set_item_multistate(int p_idx, int p_state) { @@ -1045,6 +1068,7 @@ void PopupMenu::clear() { items.clear(); mouse_over = -1; update(); + minimum_size_changed(); } Array PopupMenu::_get_items() const { diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index c6ff8489c0..55a650ff12 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -2950,13 +2950,13 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) { case KEY_A: { #ifndef APPLE_STYLE_KEYS - if (!k->get_command() || k->get_shift() || k->get_alt()) { + if (!k->get_control() || k->get_shift() || k->get_alt()) { scancode_handled = false; break; } select_all(); #else - if (k->get_alt() || (!k->get_shift() && !k->get_command() && !k->get_control())) { + if ((!k->get_command() && !k->get_control())) { scancode_handled = false; break; } @@ -4110,7 +4110,7 @@ Control::CursorShape TextEdit::get_cursor_shape(const Point2 &p_pos) const { void TextEdit::set_text(String p_text) { setting_text = true; - clear(); + _clear(); _insert_text_at_cursor(p_text); clear_undo_history(); cursor.column = 0; @@ -4123,7 +4123,7 @@ void TextEdit::set_text(String p_text) { cursor_set_column(0); update(); setting_text = false; - _text_changed_emit(); + //get_range()->set(0); }; diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp index e0562d9e4a..5b600623b9 100644 --- a/scene/resources/primitive_meshes.cpp +++ b/scene/resources/primitive_meshes.cpp @@ -676,7 +676,7 @@ void CubeMesh::_bind_methods() { ClassDB::bind_method(D_METHOD("set_subdivide_depth", "divisions"), &CubeMesh::set_subdivide_depth); ClassDB::bind_method(D_METHOD("get_subdivide_depth"), &CubeMesh::get_subdivide_depth); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "size"), "set_size", "get_size"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "size"), "set_size", "get_size"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_width", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_width", "get_subdivide_width"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_height", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_height", "get_subdivide_height"); ADD_PROPERTY(PropertyInfo(Variant::INT, "subdivide_depth", PROPERTY_HINT_RANGE, "0,100,1"), "set_subdivide_depth", "get_subdivide_depth"); diff --git a/scene/resources/style_box.cpp b/scene/resources/style_box.cpp index 7da65ac984..ebad00b068 100644 --- a/scene/resources/style_box.cpp +++ b/scene/resources/style_box.cpp @@ -136,8 +136,17 @@ Ref<Texture> StyleBoxTexture::get_normal_map() const { void StyleBoxTexture::set_margin_size(Margin p_margin, float p_size) { + ERR_FAIL_INDEX(p_margin, 4); + margin[p_margin] = p_size; emit_changed(); + static const char *margin_prop[4] = { + "content_margin_left", + "content_margin_top", + "content_margin_right", + "content_margin_bottom", + }; + _change_notify(margin_prop[p_margin]); } float StyleBoxTexture::get_margin_size(Margin p_margin) const { diff --git a/scene/resources/texture.cpp b/scene/resources/texture.cpp index 56a2e7afba..54f5aea160 100644 --- a/scene/resources/texture.cpp +++ b/scene/resources/texture.cpp @@ -76,7 +76,9 @@ void Texture::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_rect_region", "canvas_item", "rect", "src_rect", "modulate", "transpose", "normal_map", "clip_uv"), &Texture::draw_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(Variant()), DEFVAL(true)); ClassDB::bind_method(D_METHOD("get_data"), &Texture::get_data); + ADD_GROUP("Flags", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "flags", PROPERTY_HINT_FLAGS, "Mipmaps,Repeat,Filter,Anisotropic Linear,Convert to Linear,Mirrored Repeat,Video Surface"), "set_flags", "get_flags"); + ADD_GROUP("", ""); BIND_ENUM_CONSTANT(FLAGS_DEFAULT); BIND_ENUM_CONSTANT(FLAG_MIPMAPS); diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp index 42d64376f5..58057cda0c 100644 --- a/scene/resources/tile_set.cpp +++ b/scene/resources/tile_set.cpp @@ -264,7 +264,7 @@ void TileSet::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(PropertyInfo(Variant::RECT2, pre + "region")); p_list->push_back(PropertyInfo(Variant::INT, pre + "tile_mode", PROPERTY_HINT_ENUM, "SINGLE_TILE,AUTO_TILE")); if (tile_get_tile_mode(id) == AUTO_TILE) { - p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::INT, pre + "autotile/bitmask_mode", PROPERTY_HINT_ENUM, "2X2,3X3 (minimal),3X3", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::ARRAY, pre + "autotile/bitmask_flags", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/icon_coordinate", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); p_list->push_back(PropertyInfo(Variant::VECTOR2, pre + "autotile/tile_size", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); @@ -960,6 +960,7 @@ void TileSet::_bind_methods() { BIND_VMETHOD(MethodInfo(Variant::VECTOR2, "_forward_subtile_selection", PropertyInfo(Variant::INT, "autotile_id"), PropertyInfo(Variant::INT, "bitmask"), PropertyInfo(Variant::OBJECT, "tilemap", PROPERTY_HINT_NONE, "TileMap"), PropertyInfo(Variant::VECTOR2, "tile_location"))); BIND_ENUM_CONSTANT(BITMASK_2X2); + BIND_ENUM_CONSTANT(BITMASK_3X3_MINIMAL); BIND_ENUM_CONSTANT(BITMASK_3X3); BIND_ENUM_CONSTANT(BIND_TOPLEFT); diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h index d5704ac9a0..ec635ee5cc 100644 --- a/scene/resources/tile_set.h +++ b/scene/resources/tile_set.h @@ -56,6 +56,7 @@ public: enum BitmaskMode { BITMASK_2X2, + BITMASK_3X3_MINIMAL, BITMASK_3X3 }; |