diff options
Diffstat (limited to 'editor')
51 files changed, 3280 insertions, 1111 deletions
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 21ad71fe06..f94b7cd6ee 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* editor_inspector.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 "editor_inspector.h" #include "array_property_edit.h" #include "dictionary_property_edit.h" @@ -7,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 { @@ -21,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); @@ -36,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; @@ -51,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++) { @@ -63,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); + + if (bottom_editor) { - 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; + 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) { @@ -101,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 } @@ -112,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; } @@ -472,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; @@ -548,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(); @@ -596,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()) @@ -614,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() { @@ -655,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"))); @@ -667,6 +744,7 @@ void EditorProperty::_bind_methods() { EditorProperty::EditorProperty() { + selectable = true; text_size = 0; read_only = false; checkable = false; @@ -677,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; } //////////////////////////////////////////////// //////////////////////////////////////////////// @@ -725,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()) { @@ -759,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")); @@ -1066,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 @@ -1109,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(); @@ -1171,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)) @@ -1309,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); @@ -1319,13 +1475,19 @@ 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"); ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED); ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED); - ep->set_tooltip(doc_hint); + if (doc_hint != String()) { + ep->set_tooltip(TTR("Property: ") + p.name + "\n\n" + doc_hint); + } else { + 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); @@ -1364,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) { @@ -1382,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() { @@ -1399,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(); @@ -1484,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) { @@ -1619,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) @@ -1757,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); @@ -1773,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 64be316b0e..a6b183799f 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -1,18 +1,45 @@ +/*************************************************************************/ +/* editor_inspector.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 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; @@ -20,8 +47,6 @@ private: Object *object; StringName property; - LabelLayout label_layout; - int property_usage; bool read_only; @@ -39,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); @@ -92,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(); }; @@ -121,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(); }; @@ -219,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); @@ -231,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(); @@ -251,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 fb2570d472..c6d3a43f4e 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -1,7 +1,50 @@ +/*************************************************************************/ +/* editor_properties.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 "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) @@ -88,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); @@ -457,7 +500,7 @@ public: virtual String get_tooltip(const Point2 &p_pos) const { for (int i = 0; i < flag_rects.size(); i++) { - if (flag_rects[i].has_point(p_pos) && i < names.size()) { + if (i < names.size() && flag_rects[i].has_point(p_pos)) { return names[i]; } } @@ -592,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(); @@ -626,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"); @@ -1237,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; } @@ -1300,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; } @@ -1369,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; } @@ -1444,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; } @@ -1482,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(); } @@ -1922,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")) @@ -1969,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); } @@ -1985,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) { @@ -2003,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); @@ -2011,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); @@ -2022,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); @@ -2034,6 +2269,7 @@ EditorPropertyResource::EditorPropertyResource() { file = NULL; scene_tree = NULL; + dropping = false; } ////////////// DEFAULT PLUGIN ////////////////////// @@ -2051,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); @@ -2409,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 4fcef5fdae..03e72b4ec2 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* editor_properties.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 EDITOR_PROPERTIES_H #define EDITOR_PROPERTIES_H @@ -9,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; @@ -451,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; @@ -464,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); @@ -471,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/editor_settings.cpp b/editor/editor_settings.cpp index fe0392334c..a47605be15 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -1151,7 +1151,7 @@ void EditorSettings::set_project_metadata(const String &p_section, const String cf->save(path); } -Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) { +Variant EditorSettings::get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const { Ref<ConfigFile> cf = memnew(ConfigFile); String path = get_project_settings_dir().plus_file("project_metadata.cfg"); Error err = cf->load(path); @@ -1493,6 +1493,9 @@ void EditorSettings::_bind_methods() { ClassDB::bind_method(D_METHOD("get_settings_dir"), &EditorSettings::get_settings_dir); ClassDB::bind_method(D_METHOD("get_project_settings_dir"), &EditorSettings::get_project_settings_dir); + ClassDB::bind_method(D_METHOD("set_project_metadata", "section", "key", "data"), &EditorSettings::set_project_metadata); + ClassDB::bind_method(D_METHOD("get_project_metadata", "section", "key", "default"), &EditorSettings::get_project_metadata, DEFVAL(Variant())); + ClassDB::bind_method(D_METHOD("set_favorite_dirs", "dirs"), &EditorSettings::set_favorite_dirs); ClassDB::bind_method(D_METHOD("get_favorite_dirs"), &EditorSettings::get_favorite_dirs); ClassDB::bind_method(D_METHOD("set_recent_dirs", "dirs"), &EditorSettings::set_recent_dirs); diff --git a/editor/editor_settings.h b/editor/editor_settings.h index e196ca506e..b48aac89c7 100644 --- a/editor/editor_settings.h +++ b/editor/editor_settings.h @@ -167,7 +167,7 @@ public: String get_cache_dir() const; void set_project_metadata(const String &p_section, const String &p_key, Variant p_data); - Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default); + Variant get_project_metadata(const String &p_section, const String &p_key, Variant p_default) const; void set_favorite_dirs(const Vector<String> &p_favorites_dirs); Vector<String> get_favorite_dirs() const; diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 9764364273..087dcd649f 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* editor_spin_slider.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 "editor_spin_slider.h" #include "editor_scale.h" #include "os/input.h" diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index ac8d9e15d6..4956990dc2 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* editor_spin_slider.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 EDITOR_SPIN_SLIDER_H #define EDITOR_SPIN_SLIDER_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..004a49e2b4 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -109,6 +109,7 @@ void FindInFiles::start() { _current_dir = ""; PoolStringArray init_folder; init_folder.append(_root_dir); + _folders_stack.clear(); _folders_stack.push_back(init_folder); _initial_files_count = 0; @@ -127,11 +128,12 @@ void FindInFiles::_process() { // This part can be moved to a thread if needed OS &os = *OS::get_singleton(); - float duration = 0.0; - while (duration < 1.0 / 120.0) { - float time_before = os.get_ticks_msec(); + float time_before = os.get_ticks_msec(); + while (is_processing()) { _iterate(); - duration += (os.get_ticks_msec() - time_before); + float elapsed = (os.get_ticks_msec() - time_before); + if (elapsed > 1000.0 / 120.0) + break; } } @@ -428,6 +430,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/icons/icon_oriented_path_follow.svg b/editor/icons/icon_oriented_path_follow.svg new file mode 100644 index 0000000000..bd3f585e54 --- /dev/null +++ b/editor/icons/icon_oriented_path_follow.svg @@ -0,0 +1,5 @@ +<svg width="16" height="16" version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"> +<g transform="translate(0 -1036.4)"> +<path transform="translate(0 1036.4)" d="m13 0l-3 4h1.9473c-0.1385 1.3203-0.5583 1.9074-1.084 2.2754-0.64426 0.451-1.7129 0.60547-2.9629 0.73047s-2.6814 0.22053-3.9121 1.082c-0.89278 0.62493-1.5321 1.6522-1.8184 3.0957a2 2 0 0 0 -1.1699 1.8164 2 2 0 0 0 2 2 2 2 0 0 0 2 -2 2 2 0 0 0 -0.84961 -1.6328c0.19235-0.88496 0.55306-1.3373 0.98633-1.6406 0.64426-0.451 1.7129-0.60547 2.9629-0.73047s2.6814-0.22053 3.9121-1.082c1.0528-0.73697 1.7552-2.032 1.9375-3.9141h2.0508l-3-4z" fill="#fc9c9c" fill-opacity=".99608"/> +</g> +</svg> 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/resource_importer_bitmask.cpp b/editor/import/resource_importer_bitmask.cpp index a5d3959952..7b330936f6 100644 --- a/editor/import/resource_importer_bitmask.cpp +++ b/editor/import/resource_importer_bitmask.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* resource_importer_bitmask.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 "resource_importer_bitmask.h" #include "core/image.h" #include "editor/editor_file_system.h" diff --git a/editor/import/resource_importer_bitmask.h b/editor/import/resource_importer_bitmask.h index 8a3cafa7ce..f3537df819 100644 --- a/editor/import/resource_importer_bitmask.h +++ b/editor/import/resource_importer_bitmask.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* resource_importer_bitmask.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. */ +/*************************************************************************/ + #ifndef RESOURCE_IMPORTER_BITMASK_H #define RESOURCE_IMPORTER_BITMASK_H 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 0ff316a286..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")); @@ -936,41 +947,43 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int if (to > p_page_count) to = p_page_count; - Color gray = Color(0.65, 0.65, 0.65); - hbc->add_spacer(); - hbc->add_constant_override("separation", 10); + hbc->add_constant_override("separation", 5); + Button *first = memnew(Button); + first->set_text(TTR("First")); if (p_page != 0) { - LinkButton *first = memnew(LinkButton); - first->set_text(TTR("first")); - first->add_color_override("font_color", gray); - first->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); first->connect("pressed", this, "_search", varray(0)); - hbc->add_child(first); + } else { + first->set_disabled(true); + first->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(first); + Button *prev = memnew(Button); + prev->set_text(TTR("Previous")); if (p_page > 0) { - LinkButton *prev = memnew(LinkButton); - prev->set_text(TTR("prev")); - prev->add_color_override("font_color", gray); - prev->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); prev->connect("pressed", this, "_search", varray(p_page - 1)); - hbc->add_child(prev); + } else { + prev->set_disabled(true); + prev->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(prev); + hbc->add_child(memnew(VSeparator)); for (int i = from; i < to; i++) { if (i == p_page) { - Label *current = memnew(Label); + Button *current = memnew(Button); current->set_text(itos(i + 1)); + current->set_disabled(true); + current->set_focus_mode(Control::FOCUS_NONE); + hbc->add_child(current); } else { - LinkButton *current = memnew(LinkButton); - current->add_color_override("font_color", gray); - current->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); + Button *current = memnew(Button); current->set_text(itos(i + 1)); current->connect("pressed", this, "_search", varray(i)); @@ -978,28 +991,26 @@ HBoxContainer *EditorAssetLibrary::_make_pages(int p_page, int p_page_count, int } } + Button *next = memnew(Button); + next->set_text(TTR("Next")); if (p_page < p_page_count - 1) { - LinkButton *next = memnew(LinkButton); - next->set_text(TTR("next")); - next->add_color_override("font_color", gray); - next->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); next->connect("pressed", this, "_search", varray(p_page + 1)); - - hbc->add_child(next); + } else { + next->set_disabled(true); + next->set_focus_mode(Control::FOCUS_NONE); } + hbc->add_child(memnew(VSeparator)); + hbc->add_child(next); + Button *last = memnew(Button); + last->set_text(TTR("Last")); if (p_page != p_page_count - 1) { - LinkButton *last = memnew(LinkButton); - last->set_text(TTR("last")); - last->add_color_override("font_color", gray); - last->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER); - hbc->add_child(last); last->connect("pressed", this, "_search", varray(p_page_count - 1)); + } else { + last->set_disabled(true); + last->set_focus_mode(Control::FOCUS_NONE); } - - Label *totals = memnew(Label); - totals->set_text("( " + itos(from * p_page_len) + " - " + itos(from * p_page_len + p_current_items - 1) + " / " + itos(p_total_items) + " )"); - hbc->add_child(totals); + hbc->add_child(last); hbc->add_spacer(); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index f27796db5e..ca5aa7039d 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -539,6 +539,88 @@ void CanvasItemEditor::_get_canvas_items_at_pos(const Point2 &p_pos, Vector<_Sel } } +void CanvasItemEditor::_get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items) { + Point2 screen_pos = transform.xform(p_pos); + + for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { + Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); + Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().to)); + + Vector<Vector2> bone_shape; + if (!_get_bone_shape(&bone_shape, NULL, E)) + continue; + + // Check if the point is inside the Polygon2D + if (Geometry::is_point_in_polygon(screen_pos, bone_shape)) { + // Check if the item is already in the list + bool duplicate = false; + for (int i = 0; i < r_items.size(); i++) { + if (r_items[i].item == from_node) { + duplicate = true; + break; + } + } + if (duplicate) + continue; + + // Else, add it + _SelectResult res; + res.item = from_node; + res.z_index = from_node ? from_node->get_z_index() : 0; + res.has_z = from_node; + r_items.push_back(res); + } + } +} + +bool CanvasItemEditor::_get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone) { + int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width"); + int bone_outline_width = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size"); + + Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().from)); + Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(bone->key().to)); + + if (!from_node->is_inside_tree()) + return false; //may have been removed + if (!from_node) + return false; + + if (!to_node && bone->get().length == 0) + return false; + + Vector2 from = transform.xform(from_node->get_global_position()); + Vector2 to; + + if (to_node) + to = transform.xform(to_node->get_global_position()); + else + to = transform.xform(from_node->get_global_transform().xform(Vector2(bone->get().length, 0))); + + Vector2 rel = to - from; + Vector2 relt = rel.tangent().normalized() * bone_width; + Vector2 reln = rel.normalized(); + Vector2 reltn = relt.normalized(); + + if (shape) { + shape->clear(); + shape->push_back(from); + shape->push_back(from + rel * 0.2 + relt); + shape->push_back(to); + shape->push_back(from + rel * 0.2 - relt); + } + + if (outline_shape) { + outline_shape->clear(); + outline_shape->push_back(from + (-reln - reltn) * bone_outline_width); + outline_shape->push_back(from + (-reln + reltn) * bone_outline_width); + outline_shape->push_back(from + rel * 0.2 + relt + reltn * bone_outline_width); + outline_shape->push_back(to + (reln + reltn) * bone_outline_width); + outline_shape->push_back(to + (reln - reltn) * bone_outline_width); + outline_shape->push_back(from + rel * 0.2 - relt - reltn * bone_outline_width); + } + return true; +} + void CanvasItemEditor::_find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) { if (!p_node) return; @@ -1796,8 +1878,13 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { // Find the item to select CanvasItem *canvas_item = NULL; Vector<_SelectResult> selection; + + // Retrieve the items _get_canvas_items_at_pos(click, selection, editor_selection->get_selection().empty() ? 1 : 0); + // Retrieve the bones + _get_bones_at_pos(click, selection); + for (int i = 0; i < selection.size(); i++) { if (editor_selection->is_selected(selection[i].item)) { // Drag the node(s) if requested @@ -2588,57 +2675,25 @@ void CanvasItemEditor::_draw_bones() { RID ci = viewport->get_canvas_item(); if (skeleton_show_bones) { - int bone_width = EditorSettings::get_singleton()->get("editors/2d/bone_width"); Color bone_color1 = EditorSettings::get_singleton()->get("editors/2d/bone_color1"); Color bone_color2 = EditorSettings::get_singleton()->get("editors/2d/bone_color2"); Color bone_ik_color = EditorSettings::get_singleton()->get("editors/2d/bone_ik_color"); Color bone_outline_color = EditorSettings::get_singleton()->get("editors/2d/bone_outline_color"); Color bone_selected_color = EditorSettings::get_singleton()->get("editors/2d/bone_selected_color"); - int bone_outline_size = EditorSettings::get_singleton()->get("editors/2d/bone_outline_size"); for (Map<BoneKey, BoneList>::Element *E = bone_list.front(); E; E = E->next()) { - Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); - Node2D *to_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().to)); - - if (!from_node->is_inside_tree()) - continue; //may have been removed - if (!from_node) + Vector<Vector2> bone_shape; + Vector<Vector2> bone_shape_outline; + if (!_get_bone_shape(&bone_shape, &bone_shape_outline, E)) continue; - if (!to_node && E->get().length == 0) + Node2D *from_node = Object::cast_to<Node2D>(ObjectDB::get_instance(E->key().from)); + if (!from_node->is_visible_in_tree()) continue; - Vector2 from = transform.xform(from_node->get_global_position()); - Vector2 to; - - if (to_node) - to = transform.xform(to_node->get_global_position()); - else - to = transform.xform(from_node->get_global_transform().xform(Vector2(E->get().length, 0))); - - Vector2 rel = to - from; - Vector2 relt = rel.tangent().normalized() * bone_width; - Vector2 reln = rel.normalized(); - Vector2 reltn = relt.normalized(); - - Vector<Vector2> bone_shape; - bone_shape.push_back(from); - bone_shape.push_back(from + rel * 0.2 + relt); - bone_shape.push_back(to); - bone_shape.push_back(from + rel * 0.2 - relt); - - Vector<Vector2> bone_shape_outline; - bone_shape_outline.push_back(from + (-reln - reltn) * bone_outline_size); - bone_shape_outline.push_back(from + (-reln + reltn) * bone_outline_size); - bone_shape_outline.push_back(from + rel * 0.2 + relt + reltn * bone_outline_size); - bone_shape_outline.push_back(to + (reln + reltn) * bone_outline_size); - bone_shape_outline.push_back(to + (reln - reltn) * bone_outline_size); - bone_shape_outline.push_back(from + rel * 0.2 - relt - reltn * bone_outline_size); - Vector<Color> colors; if (from_node->has_meta("_edit_ik_")) { - colors.push_back(bone_ik_color); colors.push_back(bone_ik_color); colors.push_back(bone_ik_color); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index a1957b892e..4d2af11303 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -351,6 +351,7 @@ class CanvasItemEditor : public VBoxContainer { void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<_SelectResult> &r_items, int p_limit = 0, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); void _get_canvas_items_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items, int p_limit = 0); + void _get_bones_at_pos(const Point2 &p_pos, Vector<_SelectResult> &r_items); void _find_canvas_items_in_rect(const Rect2 &p_rect, Node *p_node, List<CanvasItem *> *r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D()); bool _select_click_on_item(CanvasItem *item, Point2 p_click_pos, bool p_append); @@ -379,6 +380,7 @@ class CanvasItemEditor : public VBoxContainer { UndoRedo *undo_redo; bool _build_bones_list(Node *p_node); + bool _get_bone_shape(Vector<Vector2> *shape, Vector<Vector2> *outline_shape, Map<BoneKey, BoneList>::Element *bone); List<CanvasItem *> _get_edited_canvas_items(bool retreive_locked = false, bool remove_canvas_item_if_parent_in_selection = true); Rect2 _get_encompassing_rect_from_list(List<CanvasItem *> p_list); 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 ac250f085d..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; } @@ -1549,9 +1550,10 @@ void ScriptEditor::_update_script_names() { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - String name = se->get_name(); Ref<Texture> icon = se->get_icon(); String path = se->get_edited_script()->get_path(); + bool built_in = !path.is_resource_file(); + String name = built_in ? path.get_file() : se->get_name(); _ScriptEditorItemData sd; sd.icon = icon; @@ -2680,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/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index e372f792d6..08bfebefbd 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d_editor_plugin.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 "skeleton_2d_editor_plugin.h" #include "canvas_item_editor_plugin.h" diff --git a/editor/plugins/skeleton_2d_editor_plugin.h b/editor/plugins/skeleton_2d_editor_plugin.h index bbe2a3a6f2..26ab4328b0 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.h +++ b/editor/plugins/skeleton_2d_editor_plugin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* skeleton_2d_editor_plugin.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 SKELETON_2D_EDITOR_PLUGIN_H #define SKELETON_2D_EDITOR_PLUGIN_H diff --git a/editor/plugins/sprite_editor_plugin.cpp b/editor/plugins/sprite_editor_plugin.cpp index 49816fe2ae..66673cca00 100644 --- a/editor/plugins/sprite_editor_plugin.cpp +++ b/editor/plugins/sprite_editor_plugin.cpp @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* sprite_editor_plugin.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 "sprite_editor_plugin.h" #include "canvas_item_editor_plugin.h" diff --git a/editor/plugins/sprite_editor_plugin.h b/editor/plugins/sprite_editor_plugin.h index 17aa3eb1f9..238227e4a0 100644 --- a/editor/plugins/sprite_editor_plugin.h +++ b/editor/plugins/sprite_editor_plugin.h @@ -1,3 +1,33 @@ +/*************************************************************************/ +/* sprite_editor_plugin.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 SPRITE_EDITOR_PLUGIN_H #define SPRITE_EDITOR_PLUGIN_H 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_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 385fa24ad8..c79cf02062 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -126,7 +126,7 @@ void TileSetEditor::_import_node(Node *p_node, Ref<TileSet> p_library) { Transform2D shape_transform = sb->shape_owner_get_transform(E->get()); bool one_way = sb->is_shape_owner_one_way_collision_enabled(E->get()); - shape_transform.set_origin(shape_transform.get_origin() - phys_offset); + shape_transform[2] -= phys_offset - sb->get_transform().xform(shape_transform[2]); for (int k = 0; k < sb->shape_owner_get_shape_count(E->get()); k++) { @@ -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 f5cee4cd65..b82a036130 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -75,6 +75,8 @@ void SceneTreeDock::_unhandled_key_input(Ref<InputEvent> p_event) { if (ED_IS_SHORTCUT("scene_tree/batch_rename", p_event)) { _tool_selected(TOOL_BATCH_RENAME); + } else if (ED_IS_SHORTCUT("scene_tree/rename", p_event)) { + _tool_selected(TOOL_RENAME); } else if (ED_IS_SHORTCUT("scene_tree/add_child_node", p_event)) { _tool_selected(TOOL_NEW); } else if (ED_IS_SHORTCUT("scene_tree/instance_scene", p_event)) { @@ -293,6 +295,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { rename_dialog->popup_centered(); } } break; + case TOOL_RENAME: { + Tree *tree = scene_tree->get_scene_tree(); + if (tree->is_anything_selected()) { + tree->grab_focus(); + tree->edit_selected(); + } + } break; case TOOL_NEW: { String preferred = ""; @@ -1870,7 +1879,6 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) { menu->clear(); - menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); if (selection.size() == 1) { subresources.clear(); @@ -1886,6 +1894,9 @@ 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); menu->add_separator(); + menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/rename"), TOOL_RENAME); + } else { // multi select + menu->add_icon_shortcut(get_icon("Rename", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/batch_rename"), TOOL_BATCH_RENAME); } menu->add_icon_shortcut(get_icon("Reload", "EditorIcons"), ED_GET_SHORTCUT("scene_tree/change_node_type"), TOOL_REPLACE); menu->add_separator(); @@ -1925,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)); @@ -2064,6 +2081,7 @@ SceneTreeDock::SceneTreeDock(EditorNode *p_editor, Node *p_scene_root, EditorSel filter_hbc->add_constant_override("separate", 0); ToolButton *tb; + ED_SHORTCUT("scene_tree/rename", TTR("Rename")); ED_SHORTCUT("scene_tree/batch_rename", TTR("Batch Rename"), KEY_MASK_CMD | KEY_F2); ED_SHORTCUT("scene_tree/add_child_node", TTR("Add Child Node"), KEY_MASK_CMD | KEY_A); ED_SHORTCUT("scene_tree/instance_scene", TTR("Instance Child Scene")); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index fd7d616a80..ed13e063bb 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -59,6 +59,7 @@ class SceneTreeDock : public VBoxContainer { TOOL_NEW, TOOL_INSTANCE, + TOOL_RENAME, TOOL_BATCH_RENAME, TOOL_REPLACE, TOOL_ATTACH_SCRIPT, diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 61d67d7089..687c517180 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -3261,19 +3261,19 @@ msgid "Download for this asset is already in progress!" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "first" +msgid "First" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "prev" +msgid "Previous" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "next" +msgid "Next" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp -msgid "last" +msgid "Last" msgstr "" #: editor/plugins/asset_library_editor_plugin.cpp |