/*************************************************************************/ /* editor_properties.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */ /* Copyright (c) 2014-2022 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/filesystem_dock.h" #include "editor_node.h" #include "editor_properties_array_dict.h" #include "editor_scale.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_entered(const String &p_string) { if (updating) { return; } if (text->has_focus()) { text->release_focus(); _text_changed(p_string); } } void EditorPropertyText::_text_changed(const String &p_string) { if (updating) { return; } emit_changed(get_edited_property(), p_string, "", true); } void EditorPropertyText::update_property() { String s = get_edited_object()->get(get_edited_property()); updating = true; if (text->get_text() != s) { text->set_text(s); } text->set_editable(!is_read_only()); updating = false; } void EditorPropertyText::set_placeholder(const String &p_string) { text->set_placeholder(p_string); } void EditorPropertyText::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed", "txt"), &EditorPropertyText::_text_changed); ClassDB::bind_method(D_METHOD("_text_entered", "txt"), &EditorPropertyText::_text_entered); } EditorPropertyText::EditorPropertyText() { text = memnew(LineEdit); add_child(text); add_focusable(text); text->connect("text_changed", this, "_text_changed"); text->connect("text_entered", this, "_text_entered"); updating = false; } ///////////////////// MULTILINE TEXT ///////////////////////// void EditorPropertyMultilineText::_big_text_changed() { text->set_text(big_text->get_text()); emit_changed(get_edited_property(), big_text->get_text(), "", true); } void EditorPropertyMultilineText::_text_changed() { emit_changed(get_edited_property(), text->get_text(), "", true); } void EditorPropertyMultilineText::_open_big_text() { if (!big_text_dialog) { big_text = memnew(TextEdit); big_text->connect("text_changed", this, "_big_text_changed"); big_text->set_wrap_enabled(true); big_text_dialog = memnew(AcceptDialog); big_text_dialog->add_child(big_text); big_text_dialog->set_title(TTR("Edit Text:")); add_child(big_text_dialog); } big_text_dialog->popup_centered_clamped(Size2(1000, 900) * EDSCALE, 0.8); big_text->set_text(text->get_text()); big_text->grab_focus(); } void EditorPropertyMultilineText::update_property() { String t = get_edited_object()->get(get_edited_property()); if (text->get_text() != t) { text->set_text(t); if (big_text && big_text->is_visible_in_tree()) { big_text->set_text(t); } } } void EditorPropertyMultilineText::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_ENTER_TREE: { Ref df = get_icon("DistractionFree", "EditorIcons"); open_big_text->set_icon(df); Ref font = get_font("font", "Label"); text->set_custom_minimum_size(Vector2(0, font->get_height() * 6)); } break; } } void EditorPropertyMultilineText::_bind_methods() { ClassDB::bind_method(D_METHOD("_text_changed"), &EditorPropertyMultilineText::_text_changed); ClassDB::bind_method(D_METHOD("_big_text_changed"), &EditorPropertyMultilineText::_big_text_changed); ClassDB::bind_method(D_METHOD("_open_big_text"), &EditorPropertyMultilineText::_open_big_text); } EditorPropertyMultilineText::EditorPropertyMultilineText() { HBoxContainer *hb = memnew(HBoxContainer); add_child(hb); set_bottom_editor(hb); text = memnew(TextEdit); text->connect("text_changed", this, "_text_changed"); text->set_wrap_enabled(true); add_focusable(text); hb->add_child(text); text->set_h_size_flags(SIZE_EXPAND_FILL); open_big_text = memnew(ToolButton); open_big_text->connect("pressed", this, "_open_big_text"); hb->add_child(open_big_text); big_text_dialog = nullptr; big_text = nullptr; } ///////////////////// TEXT ENUM ///////////////////////// void EditorPropertyTextEnum::_option_selected(int p_which) { emit_changed(get_edited_property(), options->get_item_text(p_which)); } void EditorPropertyTextEnum::update_property() { String which = get_edited_object()->get(get_edited_property()); for (int i = 0; i < options->get_item_count(); i++) { String t = options->get_item_text(i); if (t == which) { options->select(i); return; } } } void EditorPropertyTextEnum::setup(const Vector &p_options) { for (int i = 0; i < p_options.size(); i++) { options->add_item(p_options[i], i); } } void EditorPropertyTextEnum::_bind_methods() { ClassDB::bind_method(D_METHOD("_option_selected"), &EditorPropertyTextEnum::_option_selected); } EditorPropertyTextEnum::EditorPropertyTextEnum() { options = memnew(OptionButton); options->set_clip_text(true); options->set_flat(true); add_child(options); add_focusable(options); options->connect("item_selected", this, "_option_selected"); } ///////////////////// PATH ///////////////////////// void EditorPropertyPath::_path_selected(const String &p_path) { emit_changed(get_edited_property(), p_path); update_property(); } void EditorPropertyPath::_path_pressed() { if (!dialog) { dialog = memnew(EditorFileDialog); dialog->connect("file_selected", this, "_path_selected"); dialog->connect("dir_selected", this, "_path_selected"); add_child(dialog); } String full_path = get_edited_object()->get(get_edited_property()); dialog->clear_filters(); if (global) { dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); } else { dialog->set_access(EditorFileDialog::ACCESS_RESOURCES); } if (folder) { dialog->set_mode(EditorFileDialog::MODE_OPEN_DIR); dialog->set_current_dir(full_path); } else { dialog->set_mode(save_mode ? EditorFileDialog::MODE_SAVE_FILE : EditorFileDialog::MODE_OPEN_FILE); for (int i = 0; i < extensions.size(); i++) { String e = extensions[i].strip_edges(); if (e != String()) { dialog->add_filter(extensions[i].strip_edges()); } } dialog->set_current_path(full_path); } dialog->popup_centered_ratio(); } void EditorPropertyPath::update_property() { String full_path = get_edited_object()->get(get_edited_property()); path->set_text(full_path); path->set_tooltip(full_path); } void EditorPropertyPath::setup(const Vector &p_extensions, bool p_folder, bool p_global) { extensions = p_extensions; folder = p_folder; global = p_global; } void EditorPropertyPath::set_save_mode() { save_mode = true; } void EditorPropertyPath::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { path_edit->set_icon(get_icon("Folder", "EditorIcons")); } } void EditorPropertyPath::_path_focus_exited() { _path_selected(path->get_text()); } void EditorPropertyPath::_bind_methods() { ClassDB::bind_method(D_METHOD("_path_pressed"), &EditorPropertyPath::_path_pressed); ClassDB::bind_method(D_METHOD("_path_selected"), &EditorPropertyPath::_path_selected); ClassDB::bind_method(D_METHOD("_path_focus_exited"), &EditorPropertyPath::_path_focus_exited); } EditorPropertyPath::EditorPropertyPath() { HBoxContainer *path_hb = memnew(HBoxContainer); add_child(path_hb); path = memnew(LineEdit); path_hb->add_child(path); path->connect("text_entered", this, "_path_selected"); path->connect("focus_exited", this, "_path_focus_exited"); path->set_h_size_flags(SIZE_EXPAND_FILL); path_edit = memnew(Button); path_edit->set_clip_text(true); path_hb->add_child(path_edit); add_focusable(path); dialog = nullptr; path_edit->connect("pressed", this, "_path_pressed"); folder = false; global = false; save_mode = false; } ///////////////////// CLASS NAME ///////////////////////// void EditorPropertyClassName::setup(const String &p_base_type, const String &p_selected_type) { base_type = p_base_type; dialog->set_base_type(base_type); selected_type = p_selected_type; property->set_text(selected_type); } void EditorPropertyClassName::update_property() { String s = get_edited_object()->get(get_edited_property()); property->set_text(s); selected_type = s; } void EditorPropertyClassName::_property_selected() { dialog->popup_create(true); } void EditorPropertyClassName::_dialog_created() { selected_type = dialog->get_selected_type(); emit_changed(get_edited_property(), selected_type); update_property(); } void EditorPropertyClassName::_bind_methods() { ClassDB::bind_method(D_METHOD("_dialog_created"), &EditorPropertyClassName::_dialog_created); ClassDB::bind_method(D_METHOD("_property_selected"), &EditorPropertyClassName::_property_selected); } EditorPropertyClassName::EditorPropertyClassName() { property = memnew(Button); property->set_clip_text(true); add_child(property); add_focusable(property); property->set_text(selected_type); property->connect("pressed", this, "_property_selected"); dialog = memnew(CreateDialog); dialog->set_base_type(base_type); dialog->connect("create", this, "_dialog_created"); add_child(dialog); } ///////////////////// MEMBER ///////////////////////// void EditorPropertyMember::_property_selected(const String &p_selected) { emit_changed(get_edited_property(), p_selected); update_property(); } void EditorPropertyMember::_property_select() { if (!selector) { selector = memnew(PropertySelector); selector->connect("selected", this, "_property_selected"); add_child(selector); } String current = get_edited_object()->get(get_edited_property()); if (hint == MEMBER_METHOD_OF_VARIANT_TYPE) { Variant::Type type = Variant::NIL; for (int i = 0; i < Variant::VARIANT_MAX; i++) { if (hint_text == Variant::get_type_name(Variant::Type(i))) { type = Variant::Type(i); } } if (type != Variant::NIL) { selector->select_method_from_basic_type(type, current); } } else if (hint == MEMBER_METHOD_OF_BASE_TYPE) { selector->select_method_from_base_type(hint_text, current); } else if (hint == MEMBER_METHOD_OF_INSTANCE) { Object *instance = ObjectDB::get_instance(hint_text.to_int64()); if (instance) { selector->select_method_from_instance(instance, current); } } else if (hint == MEMBER_METHOD_OF_SCRIPT) { Object *obj = ObjectDB::get_instance(hint_text.to_int64()); if (Object::cast_to