diff options
Diffstat (limited to 'editor')
45 files changed, 928 insertions, 377 deletions
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 9f049a0e58..4ffa90777c 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -39,6 +39,7 @@ #include "editor_scale.h" #include "editor_settings.h" #include "multi_node_edit.h" +#include "scene/property_utils.h" #include "scene/resources/packed_scene.h" Size2 EditorProperty::get_minimum_size() const { @@ -305,6 +306,20 @@ void EditorProperty::_notification(int p_what) { revert_rect = Rect2(); } + if (!pin_hidden && pinned) { + Ref<Texture2D> pinned_icon = get_theme_icon(SNAME("Pin"), SNAME("EditorIcons")); + int margin_w = get_theme_constant(SNAME("hseparator"), SNAME("Tree")) * 2; + int total_icon_w = margin_w + pinned_icon->get_width(); + int text_w = font->get_string_size(label, font_size, rtl ? HALIGN_RIGHT : HALIGN_LEFT, text_limit - total_icon_w).x; + int y = (size.height - pinned_icon->get_height()) / 2; + if (rtl) { + draw_texture(pinned_icon, Vector2(size.width - ofs - text_w - total_icon_w, y), color); + } else { + draw_texture(pinned_icon, Vector2(ofs + text_w + margin_w, y), color); + } + text_limit -= total_icon_w; + } + int v_ofs = (size.height - font->get_height(font_size)) / 2; if (rtl) { draw_string(font, Point2(size.width - ofs - text_limit, v_ofs + font->get_ascent(font_size)), label, HALIGN_RIGHT, text_limit, font_size, color); @@ -398,177 +413,12 @@ bool EditorProperty::is_read_only() const { return read_only; } -bool EditorPropertyRevert::may_node_be_in_instance(Node *p_node) { - Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - - bool might_be = false; - Node *node = p_node; - - while (node) { - if (node == edited_scene) { - if (node->get_scene_inherited_state().is_valid()) { - might_be = true; - break; - } - might_be = false; - break; - } - if (node->get_scene_instance_state().is_valid()) { - might_be = true; - break; - } - node = node->get_owner(); - } - - return might_be; // or might not be -} - -bool EditorPropertyRevert::get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default) { - Node *node = p_node; - Node *orig = node; - - Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - - bool found = false; - - while (node) { - Ref<SceneState> ss; - - if (node == edited_scene) { - ss = node->get_scene_inherited_state(); - - } else { - ss = node->get_scene_instance_state(); - } - - if (ss.is_valid()) { - NodePath np = node->get_path_to(orig); - int node_idx = ss->find_node_by_path(np); - if (node_idx >= 0) { - bool lfound = false; - Variant lvar; - lvar = ss->get_property_value(node_idx, p_prop, lfound); - if (lfound) { - found = true; - value = lvar; - } - } - } - if (node == edited_scene) { - //just in case - break; - } - node = node->get_owner(); - } - - if (p_check_class_default && !found && p_node) { - //if not found, try default class value - Variant attempt = ClassDB::class_get_default_property_value(p_node->get_class_name(), p_prop); - if (attempt.get_type() != Variant::NIL) { - found = true; - value = attempt; - } - } - - return found; -} - -bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig) { - // this is a pretty difficult function, because a property may not be saved but may have - // the flag to not save if one or if zero - - //make sure there is an actual state - { - Node *node = p_node; - if (!node) { - return false; - } - - Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); - bool found_state = false; - - while (node) { - Ref<SceneState> ss; - - if (node == edited_scene) { - ss = node->get_scene_inherited_state(); - - } else { - ss = node->get_scene_instance_state(); - } - - if (ss.is_valid()) { - found_state = true; - break; - } - if (node == edited_scene) { - //just in case - break; - } - node = node->get_owner(); - } - - if (!found_state) { - return false; //pointless to check if we are not comparing against anything. - } - } - - return is_property_value_different(p_current, p_orig); -} - -bool EditorPropertyRevert::is_property_value_different(const Variant &p_a, const Variant &p_b) { - if (p_a.get_type() == Variant::FLOAT && p_b.get_type() == Variant::FLOAT) { - //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error - return !Math::is_equal_approx((float)p_a, (float)p_b); - } else { - return p_a != p_b; - } -} - Variant EditorPropertyRevert::get_property_revert_value(Object *p_object, const StringName &p_property) { - // If the object implements property_can_revert, rely on that completely - // (i.e. don't then try to revert to default value - the property_get_revert implementation - // can do that if so desired) if (p_object->has_method("property_can_revert") && p_object->call("property_can_revert", p_property)) { return p_object->call("property_get_revert", p_property); } - Ref<Script> scr = p_object->get_script(); - Node *node = Object::cast_to<Node>(p_object); - if (node && EditorPropertyRevert::may_node_be_in_instance(node)) { - //if this node is an instance or inherits, but it has a script attached which is unrelated - //to the one set for the parent and also has a default value for the property, consider that - //has precedence over the value from the parent, because that is an explicit source of defaults - //closer in the tree to the current node - bool ignore_parent = false; - if (scr.is_valid()) { - Variant sorig; - if (EditorPropertyRevert::get_instantiated_node_original_property(node, "script", sorig) && !scr->inherits_script(sorig)) { - Variant dummy; - if (scr->get_property_default_value(p_property, dummy)) { - ignore_parent = true; - } - } - } - - if (!ignore_parent) { - //check for difference including instantiation - Variant vorig; - if (EditorPropertyRevert::get_instantiated_node_original_property(node, p_property, vorig, false)) { - return vorig; - } - } - } - - if (scr.is_valid()) { - Variant orig_value; - if (scr->get_property_default_value(p_property, orig_value)) { - return orig_value; - } - } - - //report default class value instead - return ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property); + return PropertyUtils::get_property_default_value(p_object, p_property); } bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property) { @@ -577,18 +427,25 @@ bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringNam return false; } Variant current_value = p_object->get(p_property); - return EditorPropertyRevert::is_property_value_different(current_value, revert_value); + return PropertyUtils::is_property_value_different(current_value, revert_value); } -void EditorProperty::update_reload_status() { +void EditorProperty::update_revert_and_pin_status() { if (property == StringName()) { return; //no property, so nothing to do } - bool has_reload = EditorPropertyRevert::can_property_revert(object, property); + bool new_pinned = false; + if (can_pin) { + Node *node = Object::cast_to<Node>(object); + CRASH_COND(!node); + new_pinned = node->is_property_pinned(property); + } + bool new_can_revert = EditorPropertyRevert::can_property_revert(object, property) && !is_read_only(); - if (has_reload != can_revert) { - can_revert = has_reload; + if (new_can_revert != can_revert || new_pinned != pinned) { + can_revert = new_can_revert; + pinned = new_pinned; update(); } } @@ -791,7 +648,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { emit_signal(SNAME("property_checked"), property, checked); } } else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_RIGHT) { - _ensure_popup(); + _update_popup(); menu->set_position(get_screen_position() + get_local_mouse_position()); menu->set_size(Vector2(1, 1)); menu->popup(); @@ -914,6 +771,56 @@ float EditorProperty::get_name_split_ratio() const { void EditorProperty::set_object_and_property(Object *p_object, const StringName &p_property) { object = p_object; property = p_property; + _update_pin_flags(); +} + +static bool _is_value_potential_override(Node *p_node, const String &p_property) { + // Consider a value is potentially overriding another if either of the following is true: + // a) The node is foreign (inheriting or an instance), so the original value may come from another scene. + // b) The node belongs to the scene, but the original value comes from somewhere but the builtin class (i.e., a script). + Node *edited_scene = EditorNode::get_singleton()->get_edited_scene(); + Vector<SceneState::PackState> states_stack = PropertyUtils::get_node_states_stack(p_node, edited_scene); + if (states_stack.size()) { + return true; + } else { + bool is_class_default = false; + PropertyUtils::get_property_default_value(p_node, p_property, &states_stack, false, nullptr, &is_class_default); + return !is_class_default; + } +} + +void EditorProperty::_update_pin_flags() { + can_pin = false; + pin_hidden = true; + if (read_only) { + return; + } + if (Node *node = Object::cast_to<Node>(object)) { + // Avoid errors down the road by ignoring nodes which are not part of a scene + if (!node->get_owner()) { + bool is_scene_root = false; + for (int i = 0; i < EditorNode::get_singleton()->get_editor_data().get_edited_scene_count(); ++i) { + if (EditorNode::get_singleton()->get_editor_data().get_edited_scene_root(i) == node) { + is_scene_root = true; + break; + } + } + if (!is_scene_root) { + return; + } + } + if (!_is_value_potential_override(node, property)) { + return; + } + pin_hidden = false; + { + Set<StringName> storable_properties; + node->get_storable_properties(storable_properties); + if (storable_properties.has(node->get_property_store_alias(property))) { + can_pin = true; + } + } + } } Control *EditorProperty::make_custom_tooltip(const String &p_text) const { @@ -955,6 +862,10 @@ void EditorProperty::menu_option(int p_option) { case MENU_COPY_PROPERTY_PATH: { DisplayServer::get_singleton()->clipboard_set(property); } break; + case MENU_PIN_VALUE: { + emit_signal(SNAME("property_pinned"), property, !pinned); + update(); + } break; } } @@ -1003,12 +914,14 @@ void EditorProperty::_bind_methods() { ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING_NAME, "property"))); ADD_SIGNAL(MethodInfo("property_deleted", PropertyInfo(Variant::STRING_NAME, "property"))); ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT))); - ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::STRING, "bool"))); + ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "checked"))); + ADD_SIGNAL(MethodInfo("property_pinned", PropertyInfo(Variant::STRING_NAME, "property"), PropertyInfo(Variant::BOOL, "pinned"))); 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_NAME, "property"), PropertyInfo(Variant::INT, "id"))); ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx"))); GDVIRTUAL_BIND(_update_property) + ClassDB::bind_method(D_METHOD("_update_revert_and_pin_status"), &EditorProperty::update_revert_and_pin_status); } EditorProperty::EditorProperty() { @@ -1027,6 +940,9 @@ EditorProperty::EditorProperty() { revert_hover = false; check_hover = false; can_revert = false; + can_pin = false; + pin_hidden = false; + pinned = false; use_folding = false; property_usage = 0; selected = false; @@ -1038,17 +954,29 @@ EditorProperty::EditorProperty() { set_process_unhandled_key_input(true); } -void EditorProperty::_ensure_popup() { +void EditorProperty::_update_popup() { if (menu) { - return; + menu->clear(); + } else { + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &EditorProperty::menu_option)); } - menu = memnew(PopupMenu); menu->add_shortcut(ED_GET_SHORTCUT("property_editor/copy_property"), MENU_COPY_PROPERTY); menu->add_shortcut(ED_GET_SHORTCUT("property_editor/paste_property"), MENU_PASTE_PROPERTY); menu->add_shortcut(ED_GET_SHORTCUT("property_editor/copy_property_path"), MENU_COPY_PROPERTY_PATH); - menu->connect("id_pressed", callable_mp(this, &EditorProperty::menu_option)); menu->set_item_disabled(MENU_PASTE_PROPERTY, is_read_only()); - add_child(menu); + if (!pin_hidden) { + menu->add_separator(); + if (can_pin) { + menu->add_check_item(TTR("Pin value"), MENU_PIN_VALUE); + menu->set_item_checked(menu->get_item_index(MENU_PIN_VALUE), pinned); + menu->set_item_tooltip(menu->get_item_index(MENU_PIN_VALUE), TTR("Pinning a value forces it to be saved even if it's equal to the default.")); + } else { + menu->add_check_item(vformat(TTR("Pin value [Disabled because '%s' is editor-only]"), property), MENU_PIN_VALUE); + menu->set_item_disabled(menu->get_item_index(MENU_PIN_VALUE), true); + } + } } //////////////////////////////////////////////// @@ -2296,6 +2224,7 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<Edit ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), varray(), CONNECT_DEFERRED); ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value)); ep->connect("property_checked", callable_mp(this, &EditorInspector::_property_checked)); + ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned)); ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected)); ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed)); ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), varray(), CONNECT_DEFERRED); @@ -2324,7 +2253,8 @@ void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<Edit ep->set_read_only(read_only); ep->update_property(); - ep->update_reload_status(); + ep->_update_pin_flags(); + ep->update_revert_and_pin_status(); ep->set_deletable(deletable_properties); ep->update_cache(); } @@ -2877,6 +2807,7 @@ void EditorInspector::update_tree() { ep->connect("property_deleted", callable_mp(this, &EditorInspector::_property_deleted), varray(), CONNECT_DEFERRED); ep->connect("property_keyed_with_value", callable_mp(this, &EditorInspector::_property_keyed_with_value)); ep->connect("property_checked", callable_mp(this, &EditorInspector::_property_checked)); + ep->connect("property_pinned", callable_mp(this, &EditorInspector::_property_pinned)); ep->connect("selected", callable_mp(this, &EditorInspector::_property_selected)); ep->connect("multiple_properties_changed", callable_mp(this, &EditorInspector::_multiple_properties_changed)); ep->connect("resource_selected", callable_mp(this, &EditorInspector::_resource_selected), varray(), CONNECT_DEFERRED); @@ -2887,7 +2818,8 @@ void EditorInspector::update_tree() { ep->set_tooltip(property_prefix + p.name); } ep->update_property(); - ep->update_reload_status(); + ep->_update_pin_flags(); + ep->update_revert_and_pin_status(); ep->update_cache(); if (current_selected && ep->property == current_selected) { @@ -2917,7 +2849,7 @@ void EditorInspector::update_property(const String &p_prop) { for (EditorProperty *E : editor_property_map[p_prop]) { E->update_property(); - E->update_reload_status(); + E->update_revert_and_pin_status(); E->update_cache(); } } @@ -3196,7 +3128,7 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo if (editor_property_map.has(p_name)) { for (EditorProperty *E : editor_property_map[p_name]) { - E->update_reload_status(); + E->update_revert_and_pin_status(); } } } @@ -3295,7 +3227,7 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) { if (editor_property_map.has(p_path)) { for (EditorProperty *E : editor_property_map[p_path]) { E->update_property(); - E->update_reload_status(); + E->update_revert_and_pin_status(); E->update_cache(); } } @@ -3305,6 +3237,35 @@ void EditorInspector::_property_checked(const String &p_path, bool p_checked) { } } +void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) { + if (!object) { + return; + } + + Node *node = Object::cast_to<Node>(object); + ERR_FAIL_COND(!node); + + if (undo_redo) { + undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path)); + undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned); + undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned); + if (editor_property_map.has(p_path)) { + for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { + undo_redo->add_do_method(E->get(), "_update_revert_and_pin_status"); + undo_redo->add_undo_method(E->get(), "_update_revert_and_pin_status"); + } + } + undo_redo->commit_action(); + } else { + node->set_property_pinned(p_path, p_pinned); + if (editor_property_map.has(p_path)) { + for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) { + E->get()->update_revert_and_pin_status(); + } + } + } +} + void EditorInspector::_property_selected(const String &p_path, int p_focusable) { property_selected = p_path; property_focusable = p_focusable; @@ -3375,7 +3336,7 @@ void EditorInspector::_notification(int p_what) { for (EditorProperty *E : F.value) { if (!E->is_cache_valid()) { E->update_property(); - E->update_reload_status(); + E->update_revert_and_pin_status(); E->update_cache(); } } @@ -3397,7 +3358,7 @@ void EditorInspector::_notification(int p_what) { if (editor_property_map.has(prop)) { for (EditorProperty *E : editor_property_map[prop]) { E->update_property(); - E->update_reload_status(); + E->update_revert_and_pin_status(); E->update_cache(); } } @@ -3490,7 +3451,7 @@ void EditorInspector::_update_script_class_properties(const Object &p_object, Li String path = s->get_path(); String name = EditorNode::get_editor_data().script_class_get_name(path); if (name.is_empty()) { - if (!path.is_empty() && path.find("::") == -1) { + if (!s->is_built_in()) { name = path.get_file(); } else { name = TTR("Built-in script"); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 124ea31302..aabb66eeb4 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -43,7 +43,6 @@ class UndoRedo; class EditorPropertyRevert { public: - static bool may_node_be_in_instance(Node *p_node); static bool get_instantiated_node_original_property(Node *p_node, const StringName &p_prop, Variant &value, bool p_check_class_default = true); static bool is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig); static bool is_property_value_different(const Variant &p_a, const Variant &p_b); @@ -60,6 +59,7 @@ public: MENU_COPY_PROPERTY, MENU_PASTE_PROPERTY, MENU_COPY_PROPERTY_PATH, + MENU_PIN_VALUE, }; private: @@ -91,11 +91,14 @@ private: bool delete_hover = false; bool can_revert; + bool can_pin; + bool pin_hidden; + bool pinned; bool use_folding; bool draw_top_bg; - void _ensure_popup(); + void _update_popup(); void _focusable_focused(int p_index); bool selectable; @@ -114,6 +117,8 @@ private: Map<StringName, Variant> cache; GDVIRTUAL0(_update_property) + void _update_pin_flags(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -138,7 +143,7 @@ public: StringName get_edited_property(); virtual void update_property(); - void update_reload_status(); + void update_revert_and_pin_status(); virtual bool use_keying_next() const; @@ -459,8 +464,8 @@ class EditorInspector : public ScrollContainer { void _property_keyed(const String &p_path, bool p_advance); void _property_keyed_with_value(const String &p_path, const Variant &p_value, bool p_advance); void _property_deleted(const String &p_path); - void _property_checked(const String &p_path, bool p_checked); + void _property_pinned(const String &p_path, bool p_pinned); void _resource_selected(const String &p_path, RES p_resource); void _property_selected(const String &p_path, int p_focusable); diff --git a/editor/editor_log.cpp b/editor/editor_log.cpp index 251e1c2385..5f2f8e91c9 100644 --- a/editor/editor_log.cpp +++ b/editor/editor_log.cpp @@ -45,9 +45,9 @@ void EditorLog::_error_handler(void *p_self, const char *p_func, const char *p_f String err_str; if (p_errorexp && p_errorexp[0]) { - err_str = p_errorexp; + err_str = String::utf8(p_errorexp); } else { - err_str = String(p_file) + ":" + itos(p_line) + " - " + String(p_error); + err_str = String::utf8(p_file) + ":" + itos(p_line) + " - " + String::utf8(p_error); } if (p_editor_notify) { diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index bb4a05efba..4af7763caa 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -174,6 +174,7 @@ #include "editor/plugins/sprite_frames_editor_plugin.h" #include "editor/plugins/style_box_editor_plugin.h" #include "editor/plugins/sub_viewport_preview_editor_plugin.h" +#include "editor/plugins/text_control_editor_plugin.h" #include "editor/plugins/text_editor.h" #include "editor/plugins/texture_3d_editor_plugin.h" #include "editor/plugins/texture_editor_plugin.h" @@ -1791,7 +1792,7 @@ void EditorNode::_save_all_scenes() { } else { _save_scene_with_preview(scene->get_scene_file_path()); } - } else { + } else if (scene->get_scene_file_path() != "") { all_saved = false; } } @@ -2256,7 +2257,8 @@ void EditorNode::_edit_current() { if (main_plugin) { // special case if use of external editor is true - if (main_plugin->get_name() == "Script" && current_obj->get_class_name() != StringName("VisualScript") && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) { + Resource *res = Object::cast_to<Resource>(current_obj); + if (main_plugin->get_name() == "Script" && current_obj->get_class_name() != StringName("VisualScript") && res && !res->is_built_in() && (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")) || overrides_external_editor(current_obj))) { if (!changing_scene) { main_plugin->edit(current_obj); } @@ -3356,7 +3358,7 @@ void EditorNode::set_edited_scene(Node *p_scene) { if (p_scene) { if (p_scene->get_parent() != scene_root) { - scene_root->add_child(p_scene); + scene_root->add_child(p_scene, true); } } } @@ -3488,7 +3490,7 @@ void EditorNode::set_current_scene(int p_idx) { if (new_scene) { if (new_scene->get_parent() != scene_root) { - scene_root->add_child(new_scene); + scene_root->add_child(new_scene, true); } } @@ -3622,7 +3624,7 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b sdata->set_path(lpath, true); // take over path } - Node *new_scene = sdata->instantiate(PackedScene::GEN_EDIT_STATE_MAIN); + Node *new_scene = sdata->instantiate(p_set_inherited ? PackedScene::GEN_EDIT_STATE_MAIN_INHERITED : PackedScene::GEN_EDIT_STATE_MAIN); if (!new_scene) { sdata.unref(); @@ -7009,6 +7011,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(GPUParticlesCollisionSDFEditorPlugin(this))); add_editor_plugin(memnew(InputEventEditorPlugin(this))); add_editor_plugin(memnew(SubViewportPreviewEditorPlugin(this))); + add_editor_plugin(memnew(TextControlEditorPlugin(this))); for (int i = 0; i < EditorPlugins::get_plugin_count(); i++) { add_editor_plugin(EditorPlugins::create(i, this)); @@ -7139,8 +7142,6 @@ EditorNode::EditorNode() { _build_icon_type_cache(); - Node::set_human_readable_collision_renaming(true); - pick_main_scene = memnew(ConfirmationDialog); gui_base->add_child(pick_main_scene); pick_main_scene->get_ok_button()->set_text(TTR("Select")); diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp index f05c401f1d..4775ca418b 100644 --- a/editor/editor_resource_picker.cpp +++ b/editor/editor_resource_picker.cpp @@ -84,7 +84,7 @@ void EditorResourcePicker::_update_resource_preview(const String &p_path, const if (p_preview.is_valid()) { preview_rect->set_offset(SIDE_LEFT, assign_button->get_icon()->get_width() + assign_button->get_theme_stylebox(SNAME("normal"))->get_default_margin(SIDE_LEFT) + get_theme_constant(SNAME("hseparation"), SNAME("Button"))); - if (type == "GradientTexture") { + if (type == "GradientTexture1D") { preview_rect->set_stretch_mode(TextureRect::STRETCH_SCALE); assign_button->set_custom_minimum_size(Size2(1, 1)); } else { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 1da9213b89..739fc0e4f5 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -293,8 +293,8 @@ void EditorSettings::_get_property_list(List<PropertyInfo> *p_list) const { p_list->push_back(pi); } - p_list->push_back(PropertyInfo(Variant::ARRAY, "shortcuts", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); //do not edit - p_list->push_back(PropertyInfo(Variant::ARRAY, "builtin_action_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::ARRAY, "shortcuts", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); //do not edit + p_list->push_back(PropertyInfo(Variant::ARRAY, "builtin_action_overrides", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } void EditorSettings::_add_property_info_bind(const Dictionary &p_info) { diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 06c39a957c..8e8437f1b2 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -1207,7 +1207,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_shadow_color", "RichTextLabel", Color(0, 0, 0, 0)); theme->set_constant("shadow_offset_x", "RichTextLabel", 1 * EDSCALE); theme->set_constant("shadow_offset_y", "RichTextLabel", 1 * EDSCALE); - theme->set_constant("shadow_as_outline", "RichTextLabel", 0 * EDSCALE); + theme->set_constant("shadow_outline_size", "RichTextLabel", 1 * EDSCALE); theme->set_stylebox("focus", "RichTextLabel", make_empty_stylebox()); theme->set_stylebox("normal", "RichTextLabel", style_tree_bg); @@ -1223,7 +1223,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("font_shadow_color", "Label", Color(0, 0, 0, 0)); theme->set_constant("shadow_offset_x", "Label", 1 * EDSCALE); theme->set_constant("shadow_offset_y", "Label", 1 * EDSCALE); - theme->set_constant("shadow_as_outline", "Label", 0 * EDSCALE); + theme->set_constant("shadow_outline_size", "Label", 1 * EDSCALE); theme->set_constant("line_spacing", "Label", 3 * EDSCALE); // LinkButton diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp index 22da12b59b..0d9a546b8e 100644 --- a/editor/editor_toaster.cpp +++ b/editor/editor_toaster.cpp @@ -158,11 +158,11 @@ void EditorToaster::_error_handler(void *p_self, const char *p_func, const char if (p_editor_notify || (show_all_setting == 0 && in_dev) || show_all_setting == 1) { String err_str; if (p_errorexp && p_errorexp[0]) { - err_str = p_errorexp; + err_str = String::utf8(p_errorexp); } else { - err_str = String(p_error); + err_str = String::utf8(p_error); } - String tooltip_str = String(p_file) + ":" + itos(p_line); + String tooltip_str = String::utf8(p_file) + ":" + itos(p_line); if (!p_editor_notify) { if (p_type == ERR_HANDLER_WARNING) { diff --git a/editor/icons/GradientTexture.svg b/editor/icons/GradientTexture1D.svg index fa03e69805..fa03e69805 100644 --- a/editor/icons/GradientTexture.svg +++ b/editor/icons/GradientTexture1D.svg diff --git a/editor/icons/InterpCubic.svg b/editor/icons/InterpCubic.svg index ad2ed51ee1..b542986ea6 100644 --- a/editor/icons/InterpCubic.svg +++ b/editor/icons/InterpCubic.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c3 0 3-4 6-4s3 4 6 4" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4c5 0 3-4 6-4s1 4 6 4" fill="none" stroke="#5fb2ff" stroke-linecap="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg> diff --git a/editor/icons/InterpLinear.svg b/editor/icons/InterpLinear.svg index 241a82fc8f..966ddfdc31 100644 --- a/editor/icons/InterpLinear.svg +++ b/editor/icons/InterpLinear.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 6-4 6 4" fill="none" stroke="#e0e0e0" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m2 1050.4 6-4 6 4" fill="none" stroke="#ffca5f" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" transform="translate(0 -1044.4)"/></svg> diff --git a/editor/icons/InterpWrapClamp.svg b/editor/icons/InterpWrapClamp.svg index 6ba8e78500..b589542019 100644 --- a/editor/icons/InterpWrapClamp.svg +++ b/editor/icons/InterpWrapClamp.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v6h2v-2.9863-3.0137zm2 3.0137a1.0001 1.0001 0 0 0 .29297.69336l2 2a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-.29297-.29297h3.1719l-.29297.29297a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 .29297-.72266 1.0001 1.0001 0 0 0 -.29297-.69141l-2-2a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l.29297.29297h-3.1719l.29297-.29297a1 1 0 0 0 0-1.4141 1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102l-2 2a1.0001 1.0001 0 0 0 -.29297.7207zm10-.029297v3.0156h2v-6h-2z" fill="#e0e0e0"/></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v6h2v-2.9863-3.0137zm2 3.0137a1.0001 1.0001 0 0 0 .29297.69336l2 2a1 1 0 0 0 1.4141 0 1 1 0 0 0 0-1.4141l-.29297-.29297h3.1719l-.29297.29297a1 1 0 0 0 0 1.4141 1 1 0 0 0 1.4141 0l2-2a1.0001 1.0001 0 0 0 .29297-.72266 1.0001 1.0001 0 0 0 -.29297-.69141l-2-2a1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102 1 1 0 0 0 0 1.4141l.29297.29297h-3.1719l.29297-.29297a1 1 0 0 0 0-1.4141 1 1 0 0 0 -.7207-.29102 1 1 0 0 0 -.69336.29102l-2 2a1.0001 1.0001 0 0 0 -.29297.7207zm10-.029297v3.0156h2v-6h-2z" fill="#fc7f7f"/></svg> diff --git a/editor/icons/InterpWrapLoop.svg b/editor/icons/InterpWrapLoop.svg index 57670f97ce..4faf7805f8 100644 --- a/editor/icons/InterpWrapLoop.svg +++ b/editor/icons/InterpWrapLoop.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 0-3 2 3 2v-1h3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3h-3zm-5 1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h3v1l3-2-3-2v1h-3a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#e0e0e0"/></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 0-3 2 3 2v-1h3a1 1 0 0 1 1 1 1 1 0 0 1 -1 1v2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3h-3zm-5 1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h3v1l3-2-3-2v1h-3a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#c38ef1"/></svg> diff --git a/editor/icons/ReverseGradient.svg b/editor/icons/ReverseGradient.svg new file mode 100644 index 0000000000..12f80d12dd --- /dev/null +++ b/editor/icons/ReverseGradient.svg @@ -0,0 +1 @@ +<?xml version="1.0" encoding="UTF-8"?><svg version="1.1" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient id="b" x1=".26458" x2="3.9688" y1=".79375" y2=".79375" gradientTransform="scale(3.7795)" gradientUnits="userSpaceOnUse"><stop stop-color="#ccc" offset="0"/><stop stop-color="#ccc" stop-opacity="0" offset="1"/></linearGradient><linearGradient id="a" x1=".26458" x2="3.9688" y1="3.4396" y2="3.4396" gradientTransform="matrix(3.7795 0 0 3.7795 -16 -1.1865e-7)" gradientUnits="userSpaceOnUse"><stop stop-color="#ccc" offset="0"/><stop stop-color="#ccc" stop-opacity="0" offset="1"/></linearGradient></defs><g><rect x="1" y="1" width="14" height="4" ry="1" fill="url(#b)"/><rect transform="scale(-1,1)" x="-15" y="11" width="14" height="4" ry="1" fill="url(#a)" stroke-linecap="round" stroke-linejoin="round" stroke-width="3.7795"/><path d="m6 6 2 4 2-4z" fill="#ccc"/></g></svg> diff --git a/editor/icons/TrackCapture.svg b/editor/icons/TrackCapture.svg index aaa4a20e4a..b3d5f09eff 100644 --- a/editor/icons/TrackCapture.svg +++ b/editor/icons/TrackCapture.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e0e0e0"><path d="m2.1665128.99764963c-.422625 0-.763672.34104737-.763672.76367187v4.5742187c0 .4226242.341047.7617192.763672.7617192h4.472656c.422625 0 .763672-.339095.763672-.7617192v-.9882812h-3.300781c-.1662 0-.298828-.3390943-.298828-.7617188v-1.2246094c0-.4226244.132628-.7636718.298828-.7636718h3.300781v-.8359375c0-.4226245-.341047-.76367187-.763672-.76367187z"/><path d="m9.1827441 4.7953408c.5166221-1.0415625 1.0955249-2.2117429 1.2864509-2.600401l.347137-.7066511.679654.00665.679654.00665.956945 2.3125c.526319 1.271875 1.007254 2.4334375 1.068744 2.5812497l.1118.26875h-.597215-.597214l-.332849-.6437497-.332849-.64375h-1.133826-1.133825l-.3786749.6561133-.3786747.6561134-.5922856.000137-.592285.000136zm3.1779349-.369483c.0042-.00346-.233487-.4884588-.528245-1.0777779l-.535922-1.0714891-.03691.0875c-.0203.048125-.183516.425-.362699.8375-.179182.4125-.355738.85125-.392346.975-.03661.12375-.07127.2390723-.07703.2562715-.0083.024853.188215.027989.957503.015278.532385-.0088.971429-.018823.975651-.022283z" stroke="#e0e0e0" stroke-width=".803"/></g></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="#e1da5b"><path d="m2.1665128.99764963c-.422625 0-.763672.34104737-.763672.76367187v4.5742187c0 .4226242.341047.7617192.763672.7617192h4.472656c.422625 0 .763672-.339095.763672-.7617192v-.9882812h-3.300781c-.1662 0-.298828-.3390943-.298828-.7617188v-1.2246094c0-.4226244.132628-.7636718.298828-.7636718h3.300781v-.8359375c0-.4226245-.341047-.76367187-.763672-.76367187z"/><path d="m9.1827441 4.7953408c.5166221-1.0415625 1.0955249-2.2117429 1.2864509-2.600401l.347137-.7066511.679654.00665.679654.00665.956945 2.3125c.526319 1.271875 1.007254 2.4334375 1.068744 2.5812497l.1118.26875h-.597215-.597214l-.332849-.6437497-.332849-.64375h-1.133826-1.133825l-.3786749.6561133-.3786747.6561134-.5922856.000137-.592285.000136zm3.1779349-.369483c.0042-.00346-.233487-.4884588-.528245-1.0777779l-.535922-1.0714891-.03691.0875c-.0203.048125-.183516.425-.362699.8375-.179182.4125-.355738.85125-.392346.975-.03661.12375-.07127.2390723-.07703.2562715-.0083.024853.188215.027989.957503.015278.532385-.0088.971429-.018823.975651-.022283z" stroke="#e1da5b" stroke-width=".803"/></g></svg> diff --git a/editor/icons/TrackDiscrete.svg b/editor/icons/TrackDiscrete.svg index d1df4b1667..6498742233 100644 --- a/editor/icons/TrackDiscrete.svg +++ b/editor/icons/TrackDiscrete.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m14 1a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-6 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#b9ec41"/></svg> diff --git a/editor/icons/TrackTrigger.svg b/editor/icons/TrackTrigger.svg index 6e46a74121..c403fba59a 100644 --- a/editor/icons/TrackTrigger.svg +++ b/editor/icons/TrackTrigger.svg @@ -1 +1 @@ -<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v4h2v-4h2v-2zm13 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#e0e0e0"/></svg> +<svg height="8" viewBox="0 0 16 8" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 1v2h2v4h2v-4h2v-2zm13 0a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1zm-3 2a1 1 0 0 0 -1 1 1 1 0 0 0 1 1 1 1 0 0 0 1-1 1 1 0 0 0 -1-1z" fill="#f68f45"/></svg> diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index f9aa550e7d..076c0cc62b 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -314,7 +314,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) { xf = collada.fix_transform(xf) * p_node->post_transform; node->set_transform(xf); - p_parent->add_child(node); + p_parent->add_child(node, true); node->set_owner(scene); if (p_node->empty_draw_type != "") { @@ -1804,7 +1804,7 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 ap->add_animation(name, state.animations[i]); } - state.scene->add_child(ap); + state.scene->add_child(ap, true); ap->set_owner(state.scene); } diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp index 2e7ef1402b..a64be54f2d 100644 --- a/editor/import/resource_importer_bmfont.cpp +++ b/editor/import/resource_importer_bmfont.cpp @@ -359,6 +359,8 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & int height = 0; int ascent = 0; int outline = 0; + uint32_t st_flags = 0; + String font_name; bool packed = false; uint8_t ch[4] = { 0, 0, 0, 0 }; // RGBA @@ -382,13 +384,23 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & base_size = f->get_16(); uint8_t flags = f->get_8(); ERR_FAIL_COND_V_MSG(flags & 0x02, ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported.")); + if (flags & (1 << 3)) { + st_flags |= TextServer::FONT_BOLD; + } + if (flags & (1 << 2)) { + st_flags |= TextServer::FONT_ITALIC; + } f->get_8(); // non-unicode charset, skip f->get_16(); // stretch_h, skip f->get_8(); // aa, skip f->get_32(); // padding, skip f->get_16(); // spacing, skip outline = f->get_8(); - // font name, skip + // font name + PackedByteArray name_data; + name_data.resize(block_size - 14); + f->get_buffer(name_data.ptrw(), block_size - 14); + font_name = String::utf8((const char *)name_data.ptr(), block_size - 14); font->set_fixed_size(base_size); } break; case 2: /* common */ { @@ -601,6 +613,19 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & if (keys.has("outline")) { outline = keys["outline"].to_int(); } + if (keys.has("bold")) { + if (keys["bold"].to_int()) { + st_flags |= TextServer::FONT_BOLD; + } + } + if (keys.has("italic")) { + if (keys["italic"].to_int()) { + st_flags |= TextServer::FONT_ITALIC; + } + } + if (keys.has("face")) { + font_name = keys["face"]; + } ERR_FAIL_COND_V_MSG((!keys.has("unicode") || keys["unicode"].to_int() != 1), ERR_CANT_CREATE, TTR("Non-unicode version of BMFont is not supported.")); } else if (type == "common") { if (keys.has("lineHeight")) { @@ -778,6 +803,8 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & } } + font->set_font_name(font_name); + font->set_font_style(st_flags); font->set_ascent(0, base_size, ascent); font->set_descent(0, base_size, height - ascent); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 4f75faedcb..01af75c338 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -448,7 +448,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, in ImporterMeshInstance3D *mi = memnew(ImporterMeshInstance3D); mi->set_mesh(mesh); mi->set_name(m->get_name()); - scene->add_child(mi); + scene->add_child(mi, true); mi->set_owner(scene); } diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index 7d3b945b04..5efb08b95d 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -502,7 +502,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I sphereShape->set_radius(1); colshape->set_shape(sphereShape); } - sb->add_child(colshape); + sb->add_child(colshape, true); colshape->set_owner(sb->get_owner()); } @@ -528,7 +528,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I rigid_body->set_transform(mi->get_transform()); p_node = rigid_body; mi->set_transform(Transform3D()); - rigid_body->add_child(mi); + rigid_body->add_child(mi, true); mi->set_owner(rigid_body->get_owner()); _add_shapes(rigid_body, shapes); @@ -566,7 +566,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (shapes.size()) { StaticBody3D *col = memnew(StaticBody3D); - mi->add_child(col); + mi->add_child(col, true); col->set_owner(mi->get_owner()); _add_shapes(col, shapes); @@ -614,7 +614,7 @@ Node *ResourceImporterScene::_pre_fix_node(Node *p_node, Node *p_root, Map<Ref<I if (shapes.size()) { StaticBody3D *col = memnew(StaticBody3D); - p_node->add_child(col); + p_node->add_child(col, true); col->set_owner(p_node->get_owner()); _add_shapes(col, shapes); @@ -749,7 +749,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< switch (mesh_physics_mode) { case MESH_PHYSICS_MESH_AND_STATIC_COLLIDER: { StaticBody3D *col = memnew(StaticBody3D); - p_node->add_child(col); + p_node->add_child(col, true); col->set_owner(p_node->get_owner()); col->set_transform(get_collision_shapes_transform(node_settings)); base = col; @@ -761,7 +761,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< rigid_body->set_transform(mi->get_transform() * get_collision_shapes_transform(node_settings)); p_node = rigid_body; mi->set_transform(Transform3D()); - rigid_body->add_child(mi); + rigid_body->add_child(mi, true); mi->set_owner(rigid_body->get_owner()); base = rigid_body; } break; @@ -790,7 +790,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< for (const Ref<Shape3D> &E : shapes) { CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(E); - base->add_child(cshape); + base->add_child(cshape, true); cshape->set_owner(base->get_owner()); idx++; @@ -823,7 +823,7 @@ Node *ResourceImporterScene::_post_fix_node(Node *p_node, Node *p_root, Map<Ref< memdelete(p_node); p_node = nmi; } else { - mi->add_child(nmi); + mi->add_child(nmi, true); nmi->set_owner(mi->get_owner()); } } @@ -1431,7 +1431,7 @@ void ResourceImporterScene::get_import_options(List<ImportOption> *r_options, in r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 15)); r_options->push_back(ImportOption(PropertyInfo(Variant::STRING, "import_script/path", PROPERTY_HINT_FILE, script_ext_hint), "")); - r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR), Dictionary())); + r_options->push_back(ImportOption(PropertyInfo(Variant::DICTIONARY, "_subresources", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR), Dictionary())); for (int i = 0; i < post_importer_plugins.size(); i++) { post_importer_plugins.write[i]->get_import_options(r_options); @@ -1680,7 +1680,7 @@ void ResourceImporterScene::_add_shapes(Node *p_node, const Vector<Ref<Shape3D>> for (const Ref<Shape3D> &E : p_shapes) { CollisionShape3D *cshape = memnew(CollisionShape3D); cshape->set_shape(E); - p_node->add_child(cshape); + p_node->add_child(cshape, true); cshape->set_owner(p_node->get_owner()); } diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp index 95a96f9e26..9b9320ad6d 100644 --- a/editor/import/scene_import_settings.cpp +++ b/editor/import/scene_import_settings.cpp @@ -327,7 +327,7 @@ void SceneImportSettings::_fill_scene(Node *p_node, TreeItem *p_parent_item) { MeshInstance3D *collider_view = memnew(MeshInstance3D); collider_view->set_name("collider_view"); collider_view->set_visible(false); - mesh_node->add_child(collider_view); + mesh_node->add_child(collider_view, true); collider_view->set_owner(mesh_node); Transform3D accum_xform; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 0e1bdf0155..061483decf 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2264,9 +2264,9 @@ bool CanvasItemEditor::_gui_input_select(const Ref<InputEvent> &p_event) { } } - if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && b->is_ctrl_pressed()) { - add_node_menu->set_position(get_global_transform().xform(get_local_mouse_position())); + if (b.is_valid() && b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT) { add_node_menu->set_size(Vector2(1, 1)); + add_node_menu->set_position(get_screen_position() + b->get_position()); add_node_menu->popup(); node_create_position = transform.affine_inverse().xform((get_local_mouse_position())); return true; @@ -5836,7 +5836,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(ResourceCache::get(path))); if (parent) { - editor_data->get_undo_redo().add_do_method(parent, "add_child", child); + editor_data->get_undo_redo().add_do_method(parent, "add_child", child, true); editor_data->get_undo_redo().add_do_method(child, "set_owner", editor->get_edited_scene()); editor_data->get_undo_redo().add_do_reference(child); editor_data->get_undo_redo().add_undo_method(parent, "remove_child", child); @@ -6192,14 +6192,14 @@ CanvasItemEditorViewport::CanvasItemEditorViewport(EditorNode *p_node, CanvasIte label = memnew(Label); label->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 1)); - label->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE); + label->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); label->hide(); canvas_item_editor->get_controls_container()->add_child(label); label_desc = memnew(Label); label_desc->add_theme_color_override("font_color", Color(0.6f, 0.6f, 0.6f, 1)); label_desc->add_theme_color_override("font_shadow_color", Color(0.2f, 0.2f, 0.2f, 1)); - label_desc->add_theme_constant_override("shadow_as_outline", 1 * EDSCALE); + label_desc->add_theme_constant_override("shadow_outline_size", 1 * EDSCALE); label_desc->add_theme_constant_override("line_spacing", 0); label_desc->hide(); canvas_item_editor->get_controls_container()->add_child(label_desc); diff --git a/editor/plugins/editor_preview_plugins.cpp b/editor/plugins/editor_preview_plugins.cpp index 4cb2c0a76b..9702c7e734 100644 --- a/editor/plugins/editor_preview_plugins.cpp +++ b/editor/plugins/editor_preview_plugins.cpp @@ -297,12 +297,14 @@ EditorPackedScenePreviewPlugin::EditorPackedScenePreviewPlugin() { ////////////////////////////////////////////////////////////////// -void EditorMaterialPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done.set(); +void EditorMaterialPreviewPlugin::_generate_frame_started() { + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture + + RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_preview_done)); } -void EditorMaterialPreviewPlugin::_bind_methods() { - ClassDB::bind_method("_preview_done", &EditorMaterialPreviewPlugin::_preview_done); +void EditorMaterialPreviewPlugin::_preview_done() { + preview_done.post(); } bool EditorMaterialPreviewPlugin::handles(const String &p_type) const { @@ -320,14 +322,9 @@ Ref<Texture2D> EditorMaterialPreviewPlugin::generate(const RES &p_from, const Si if (material->get_shader_mode() == Shader::MODE_SPATIAL) { RS::get_singleton()->mesh_surface_set_material(sphere, 0, material->get_rid()); - RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture + RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMaterialPreviewPlugin *>(this), &EditorMaterialPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT); - preview_done.clear(); - RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMaterialPreviewPlugin *>(this), "_preview_done", Variant()); - - while (!preview_done.is_set()) { - OS::get_singleton()->delay_usec(10); - } + preview_done.wait(); Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); RS::get_singleton()->mesh_surface_set_material(sphere, 0, RID()); @@ -699,12 +696,14 @@ EditorAudioStreamPreviewPlugin::EditorAudioStreamPreviewPlugin() { /////////////////////////////////////////////////////////////////////////// -void EditorMeshPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done.set(); +void EditorMeshPreviewPlugin::_generate_frame_started() { + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture + + RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_preview_done)); } -void EditorMeshPreviewPlugin::_bind_methods() { - ClassDB::bind_method("_preview_done", &EditorMeshPreviewPlugin::_preview_done); +void EditorMeshPreviewPlugin::_preview_done() { + preview_done.post(); } bool EditorMeshPreviewPlugin::handles(const String &p_type) const { @@ -735,14 +734,9 @@ Ref<Texture2D> EditorMeshPreviewPlugin::generate(const RES &p_from, const Size2 xform.origin.z -= rot_aabb.size.z * 2; RS::get_singleton()->instance_set_transform(mesh_instance, xform); - RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture + RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorMeshPreviewPlugin *>(this), &EditorMeshPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT); - preview_done.clear(); - RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorMeshPreviewPlugin *>(this), "_preview_done", Variant()); - - while (!preview_done.is_set()) { - OS::get_singleton()->delay_usec(10); - } + preview_done.wait(); Ref<Image> img = RS::get_singleton()->texture_2d_get(viewport_texture); ERR_FAIL_COND_V(img.is_null(), Ref<ImageTexture>()); @@ -814,12 +808,14 @@ EditorMeshPreviewPlugin::~EditorMeshPreviewPlugin() { /////////////////////////////////////////////////////////////////////////// -void EditorFontPreviewPlugin::_preview_done(const Variant &p_udata) { - preview_done.set(); +void EditorFontPreviewPlugin::_generate_frame_started() { + RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture + + RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_preview_done)); } -void EditorFontPreviewPlugin::_bind_methods() { - ClassDB::bind_method("_preview_done", &EditorFontPreviewPlugin::_preview_done); +void EditorFontPreviewPlugin::_preview_done() { + preview_done.post(); } bool EditorFontPreviewPlugin::handles(const String &p_type) const { @@ -857,13 +853,9 @@ Ref<Texture2D> EditorFontPreviewPlugin::generate_from_path(const String &p_path, font->draw_string(canvas_item, pos, sample, HALIGN_LEFT, -1.f, 50, Color(1, 1, 1)); - preview_done.clear(); - RS::get_singleton()->viewport_set_update_mode(viewport, RS::VIEWPORT_UPDATE_ONCE); //once used for capture - RS::get_singleton()->request_frame_drawn_callback(const_cast<EditorFontPreviewPlugin *>(this), "_preview_done", Variant()); + RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<EditorFontPreviewPlugin *>(this), &EditorFontPreviewPlugin::_generate_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT); - while (!preview_done.is_set()) { - OS::get_singleton()->delay_usec(10); - } + preview_done.wait(); RS::get_singleton()->canvas_item_clear(canvas_item); diff --git a/editor/plugins/editor_preview_plugins.h b/editor/plugins/editor_preview_plugins.h index 091feae5fb..bf52f5771d 100644 --- a/editor/plugins/editor_preview_plugins.h +++ b/editor/plugins/editor_preview_plugins.h @@ -92,12 +92,10 @@ class EditorMaterialPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - mutable SafeFlag preview_done; + Semaphore preview_done; - void _preview_done(const Variant &p_udata); - -protected: - static void _bind_methods(); + void _generate_frame_started(); + void _preview_done(); public: virtual bool handles(const String &p_type) const override; @@ -136,12 +134,10 @@ class EditorMeshPreviewPlugin : public EditorResourcePreviewGenerator { RID light2; RID light_instance2; RID camera; - mutable SafeFlag preview_done; - - void _preview_done(const Variant &p_udata); + Semaphore preview_done; -protected: - static void _bind_methods(); + void _generate_frame_started(); + void _preview_done(); public: virtual bool handles(const String &p_type) const override; @@ -158,12 +154,10 @@ class EditorFontPreviewPlugin : public EditorResourcePreviewGenerator { RID viewport_texture; RID canvas; RID canvas_item; - mutable SafeFlag preview_done; + Semaphore preview_done; - void _preview_done(const Variant &p_udata); - -protected: - static void _bind_methods(); + void _generate_frame_started(); + void _preview_done(); public: virtual bool handles(const String &p_type) const override; @@ -177,12 +171,10 @@ public: class EditorTileMapPatternPreviewPlugin : public EditorResourcePreviewGenerator { GDCLASS(EditorTileMapPatternPreviewPlugin, EditorResourcePreviewGenerator); - mutable SafeFlag preview_done; - - void _preview_done(const Variant &p_udata); + Semaphore preview_done; -protected: - static void _bind_methods(); + void _generate_frame_started(); + void _preview_done(); public: virtual bool handles(const String &p_type) const override; diff --git a/editor/plugins/gradient_editor_plugin.cpp b/editor/plugins/gradient_editor_plugin.cpp index 355bdb69d8..da050abc02 100644 --- a/editor/plugins/gradient_editor_plugin.cpp +++ b/editor/plugins/gradient_editor_plugin.cpp @@ -46,6 +46,8 @@ void GradientEditor::_gradient_changed() { editing = true; Vector<Gradient::Point> points = gradient->get_points(); set_points(points); + set_interpolation_mode(gradient->get_interpolation_mode()); + update(); editing = false; } @@ -55,8 +57,10 @@ void GradientEditor::_ramp_changed() { undo_redo->create_action(TTR("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_do_method(gradient.ptr(), "set_interpolation_mode", get_interpolation_mode()); 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->add_undo_method(gradient.ptr(), "set_interpolation_mode", gradient->get_interpolation_mode()); undo_redo->commit_action(); editing = false; } @@ -69,6 +73,14 @@ void GradientEditor::set_gradient(const Ref<Gradient> &p_gradient) { connect("ramp_changed", callable_mp(this, &GradientEditor::_ramp_changed)); gradient->connect("changed", callable_mp(this, &GradientEditor::_gradient_changed)); set_points(gradient->get_points()); + set_interpolation_mode(gradient->get_interpolation_mode()); +} + +void GradientEditor::reverse_gradient() { + gradient->reverse(); + set_points(gradient->get_points()); + emit_signal(SNAME("ramp_changed")); + update(); } GradientEditor::GradientEditor() { @@ -77,6 +89,23 @@ GradientEditor::GradientEditor() { /////////////////////// +void GradientReverseButton::_notification(int p_what) { + if (p_what == NOTIFICATION_DRAW) { + Ref<Texture2D> icon = get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons")); + if (is_pressed()) { + draw_texture_rect(icon, Rect2(margin, margin, icon->get_width(), icon->get_height()), false, get_theme_color(SNAME("icon_pressed_color"), SNAME("Button"))); + } else { + draw_texture_rect(icon, Rect2(margin, margin, icon->get_width(), icon->get_height())); + } + } +} + +Size2 GradientReverseButton::get_minimum_size() const { + return (get_theme_icon(SNAME("ReverseGradient"), SNAME("EditorIcons"))->get_size() + Size2(margin * 2, margin * 2)); +} + +/////////////////////// + bool EditorInspectorPluginGradient::can_handle(Object *p_object) { return Object::cast_to<Gradient>(p_object) != nullptr; } @@ -85,9 +114,23 @@ void EditorInspectorPluginGradient::parse_begin(Object *p_object) { Gradient *gradient = Object::cast_to<Gradient>(p_object); Ref<Gradient> g(gradient); - GradientEditor *editor = memnew(GradientEditor); + editor = memnew(GradientEditor); editor->set_gradient(g); add_custom_control(editor); + + reverse_btn = memnew(GradientReverseButton); + + gradient_tools_hbox = memnew(HBoxContainer); + gradient_tools_hbox->add_child(reverse_btn); + + add_custom_control(gradient_tools_hbox); + + reverse_btn->connect("pressed", callable_mp(this, &EditorInspectorPluginGradient::_reverse_button_pressed)); + reverse_btn->set_tooltip(TTR("Reverse/mirror gradient.")); +} + +void EditorInspectorPluginGradient::_reverse_button_pressed() { + editor->reverse_gradient(); } GradientEditorPlugin::GradientEditorPlugin(EditorNode *p_node) { diff --git a/editor/plugins/gradient_editor_plugin.h b/editor/plugins/gradient_editor_plugin.h index bcbb86e422..95b7b466c9 100644 --- a/editor/plugins/gradient_editor_plugin.h +++ b/editor/plugins/gradient_editor_plugin.h @@ -50,12 +50,28 @@ protected: public: virtual Size2 get_minimum_size() const override; void set_gradient(const Ref<Gradient> &p_gradient); + void reverse_gradient(); GradientEditor(); }; +class GradientReverseButton : public BaseButton { + GDCLASS(GradientReverseButton, BaseButton); + + int margin = 2; + + void _notification(int p_what); + virtual Size2 get_minimum_size() const override; +}; + class EditorInspectorPluginGradient : public EditorInspectorPlugin { GDCLASS(EditorInspectorPluginGradient, EditorInspectorPlugin); + GradientEditor *editor; + HBoxContainer *gradient_tools_hbox; + GradientReverseButton *reverse_btn; + + void _reverse_button_pressed(); + public: virtual bool can_handle(Object *p_object) override; virtual void parse_begin(Object *p_object) override; diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 574d3ef27e..7a85c5167b 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -79,7 +79,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = node == get_tree()->get_edited_scene_root() ? node : node->get_owner(); ur->create_action(TTR("Create Static Trimesh Body")); - ur->add_do_method(node, "add_child", body); + ur->add_do_method(node, "add_child", body, true); ur->add_do_method(body, "set_owner", owner); ur->add_do_method(cshape, "set_owner", owner); ur->add_do_reference(body); @@ -113,7 +113,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = instance == get_tree()->get_edited_scene_root() ? instance : instance->get_owner(); - ur->add_do_method(instance, "add_child", body); + ur->add_do_method(instance, "add_child", body, true); ur->add_do_method(body, "set_owner", owner); ur->add_do_method(cshape, "set_owner", owner); ur->add_do_reference(body); @@ -146,7 +146,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->create_action(TTR("Create Trimesh Static Shape")); - ur->add_do_method(node->get_parent(), "add_child", cshape); + ur->add_do_method(node->get_parent(), "add_child", cshape, true); ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); ur->add_do_method(cshape, "set_owner", owner); ur->add_do_reference(cshape); @@ -185,7 +185,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { Node *owner = node->get_owner(); - ur->add_do_method(node->get_parent(), "add_child", cshape); + ur->add_do_method(node->get_parent(), "add_child", cshape, true); ur->add_do_method(node->get_parent(), "move_child", cshape, node->get_index() + 1); ur->add_do_method(cshape, "set_owner", owner); ur->add_do_reference(cshape); @@ -247,7 +247,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); ur->create_action(TTR("Create Navigation Mesh")); - ur->add_do_method(node, "add_child", nmi); + ur->add_do_method(node, "add_child", nmi, true); ur->add_do_method(nmi, "set_owner", owner); ur->add_do_reference(nmi); @@ -426,7 +426,7 @@ void MeshInstance3DEditor::_create_outline_mesh() { ur->create_action(TTR("Create Outline")); - ur->add_do_method(node, "add_child", mi); + ur->add_do_method(node, "add_child", mi, true); ur->add_do_method(mi, "set_owner", owner); ur->add_do_reference(mi); diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index b99ccc1012..fa5381bb10 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -3936,9 +3936,13 @@ Vector3 Node3DEditorViewport::_get_instance_position(const Point2 &p_pos) const Vector3 point = world_pos + world_ray * MAX_DISTANCE; PhysicsDirectSpaceState3D *ss = get_tree()->get_root()->get_world_3d()->get_direct_space_state(); - PhysicsDirectSpaceState3D::RayResult result; - if (ss->intersect_ray(world_pos, world_pos + world_ray * MAX_DISTANCE, result)) { + PhysicsDirectSpaceState3D::RayParameters ray_params; + ray_params.from = world_pos; + ray_params.to = world_pos + world_ray * MAX_DISTANCE; + + PhysicsDirectSpaceState3D::RayResult result; + if (ss->intersect_ray(ray_params, result)) { point = result.position; } @@ -6566,7 +6570,12 @@ void Node3DEditor::snap_selected_nodes_to_floor() { Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); Set<RID> excluded = _get_physics_bodies_rid(sp); - if (ss->intersect_ray(from, to, result, excluded)) { + PhysicsDirectSpaceState3D::RayParameters ray_params; + ray_params.from = from; + ray_params.to = to; + ray_params.exclude = excluded; + + if (ss->intersect_ray(ray_params, result)) { snapped_to_floor = true; } } @@ -6583,7 +6592,12 @@ void Node3DEditor::snap_selected_nodes_to_floor() { Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); Set<RID> excluded = _get_physics_bodies_rid(sp); - if (ss->intersect_ray(from, to, result, excluded)) { + PhysicsDirectSpaceState3D::RayParameters ray_params; + ray_params.from = from; + ray_params.to = to; + ray_params.exclude = excluded; + + if (ss->intersect_ray(ray_params, result)) { Vector3 position_offset = d["position_offset"]; Transform3D new_transform = sp->get_global_transform(); @@ -6636,7 +6650,7 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) { Node *new_sun = preview_sun->duplicate(); undo_redo->create_action(TTR("Add Preview Sun to Scene")); - undo_redo->add_do_method(base, "add_child", new_sun); + undo_redo->add_do_method(base, "add_child", new_sun, true); // Move to the beginning of the scene tree since more "global" nodes // generally look better when placed at the top. undo_redo->add_do_method(base, "move_child", new_sun, 0); @@ -6666,7 +6680,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) { new_env->set_environment(preview_environment->get_environment()->duplicate(true)); undo_redo->create_action(TTR("Add Preview Environment to Scene")); - undo_redo->add_do_method(base, "add_child", new_env); + undo_redo->add_do_method(base, "add_child", new_env, true); // Move to the beginning of the scene tree since more "global" nodes // generally look better when placed at the top. undo_redo->add_do_method(base, "move_child", new_env, 0); @@ -7132,7 +7146,7 @@ void Node3DEditor::_update_preview_environment() { } else { if (!preview_sun->get_parent()) { - add_child(preview_sun); + add_child(preview_sun, true); sun_state->hide(); sun_vb->show(); } diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 3f98560a2f..aad378ecec 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -227,12 +227,6 @@ void ScriptEditorBase::_bind_methods() { ADD_SIGNAL(MethodInfo("replace_in_files_requested", PropertyInfo(Variant::STRING, "text"))); } -static bool _is_built_in_script(Script *p_script) { - String path = p_script->get_path(); - - return path.find("::") != -1; -} - class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache { struct Cache { uint64_t time_loaded = 0; @@ -764,7 +758,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { if (p_save && file.is_valid()) { // Do not try to save internal scripts, but prompt to save in-memory // scripts which are not saved to disk yet (have empty path). - if (file->get_path().find("local://") == -1 && file->get_path().find("::") == -1) { + if (file->is_built_in()) { save_current_script(); } } @@ -910,7 +904,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) { RES script = se->get_edited_resource(); - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { + if (script->is_built_in()) { continue; //internal script, who cares } @@ -951,7 +945,7 @@ void ScriptEditor::_reload_scripts() { RES edited_res = se->get_edited_resource(); - if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) { + if (edited_res->is_built_in()) { continue; //internal script, who cares } @@ -995,7 +989,7 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { RES script = se->get_edited_resource(); - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { + if (script->is_built_in()) { continue; //internal script, who cares } @@ -1037,7 +1031,7 @@ bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { continue; } - if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) { + if (edited_res->is_built_in()) { continue; //internal script, who cares } @@ -1624,7 +1618,7 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) { continue; } - if (script->get_path().find("::") != -1 && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed + if (script->is_built_in() && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed _close_tab(i); i--; } @@ -2180,9 +2174,10 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra Ref<Script> script = p_resource; // Don't open dominant script if using an external editor. - const bool use_external_editor = + bool use_external_editor = EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") || (script.is_valid() && script->get_language()->overrides_external_editor()); + use_external_editor = use_external_editor && !(script.is_valid() && script->is_built_in()); // Ignore external editor for built-in scripts. const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/behavior/files/open_dominant_script_on_scene_change"); const bool should_open = (open_dominant && !use_external_editor) || !EditorNode::get_singleton()->is_changing_scene(); @@ -2450,7 +2445,7 @@ void ScriptEditor::save_all_scripts() { se->apply_code(); } - if (edited_res->get_path() != "" && edited_res->get_path().find("local://") == -1 && edited_res->get_path().find("::") == -1) { + if (!edited_res->is_built_in()) { Ref<TextFile> text_file = edited_res; Ref<Script> script = edited_res; @@ -2570,7 +2565,7 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const script_list->select(script_list->find_metadata(i)); // Save the current script so the changes can be picked up by an external editor. - if (!_is_built_in_script(script.ptr())) { // But only if it's not built-in script. + if (!script.ptr()->is_built_in()) { // But only if it's not built-in script. save_current_script(); } @@ -3346,9 +3341,10 @@ Array ScriptEditor::_get_open_script_editors() const { void ScriptEditor::set_scene_root_script(Ref<Script> p_script) { // Don't open dominant script if using an external editor. - const bool use_external_editor = + bool use_external_editor = EditorSettings::get_singleton()->get("text_editor/external/use_external_editor") || (p_script.is_valid() && p_script->get_language()->overrides_external_editor()); + use_external_editor = use_external_editor && !(p_script.is_valid() && p_script->is_built_in()); // Ignore external editor for built-in scripts. const bool open_dominant = EditorSettings::get_singleton()->get("text_editor/behavior/files/open_dominant_script_on_scene_change"); if (open_dominant && !use_external_editor && p_script.is_valid()) { @@ -3858,7 +3854,7 @@ void ScriptEditorPlugin::edit(Object *p_object) { Script *p_script = Object::cast_to<Script>(p_object); String res_path = p_script->get_path().get_slice("::", 0); - if (_is_built_in_script(p_script)) { + if (p_script->is_built_in()) { if (ResourceLoader::get_resource_type(res_path) == "PackedScene") { if (!EditorNode::get_singleton()->is_scene_open(res_path)) { EditorNode::get_singleton()->load_scene(res_path); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 219498b5e7..24cdc06d78 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -375,7 +375,7 @@ void ScriptTextEditor::ensure_focus() { String ScriptTextEditor::get_name() { String name; - if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) { + if (!script->is_built_in()) { name = script->get_path().get_file(); if (is_unsaved()) { if (script->get_path().is_empty()) { @@ -658,7 +658,7 @@ void ScriptEditor::_update_modified_scripts_for_external_editor(Ref<Script> p_fo continue; } - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { + if (script->is_built_in()) { continue; //internal script, who cares, though weird } diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 2731582288..9d2b4c88c5 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -482,8 +482,7 @@ void ShaderEditor::_check_for_external_edit() { return; } - // internal shader. - if (shader->get_path() == "" || shader->get_path().find("local://") != -1 || shader->get_path().find("::") != -1) { + if (shader->is_built_in()) { return; } @@ -530,7 +529,7 @@ void ShaderEditor::save_external_data(const String &p_str) { } apply_shaders(); - if (shader->get_path() != "" && shader->get_path().find("local://") == -1 && shader->get_path().find("::") == -1) { + if (!shader->is_built_in()) { //external shader, save it ResourceSaver::save(shader->get_path(), shader); } diff --git a/editor/plugins/text_control_editor_plugin.cpp b/editor/plugins/text_control_editor_plugin.cpp new file mode 100644 index 0000000000..c878c83430 --- /dev/null +++ b/editor/plugins/text_control_editor_plugin.cpp @@ -0,0 +1,375 @@ +/*************************************************************************/ +/* text_control_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 "text_control_editor_plugin.h" + +#include "editor/editor_scale.h" + +void TextControlEditor::_notification(int p_notification) { + switch (p_notification) { + case NOTIFICATION_ENTER_TREE: { + if (!EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) { + EditorFileSystem::get_singleton()->connect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts), make_binds("")); + } + [[fallthrough]]; + } + case NOTIFICATION_THEME_CHANGED: { + clear_formatting->set_icon(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"))); + } break; + case NOTIFICATION_EXIT_TREE: { + if (EditorFileSystem::get_singleton()->is_connected("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts))) { + EditorFileSystem::get_singleton()->disconnect("filesystem_changed", callable_mp(this, &TextControlEditor::_reload_fonts)); + } + } break; + default: + break; + } +} + +void TextControlEditor::_find_resources(EditorFileSystemDirectory *p_dir) { + for (int i = 0; i < p_dir->get_subdir_count(); i++) { + _find_resources(p_dir->get_subdir(i)); + } + + for (int i = 0; i < p_dir->get_file_count(); i++) { + if (p_dir->get_file_type(i) == "FontData") { + Ref<FontData> fd = ResourceLoader::load(p_dir->get_file_path(i)); + if (fd.is_valid()) { + String name = fd->get_font_name(); + String sty = fd->get_font_style_name(); + if (sty.is_empty()) { + sty = "Default"; + } + fonts[name][sty] = p_dir->get_file_path(i); + } + } + } +} + +void TextControlEditor::_reload_fonts(const String &p_path) { + fonts.clear(); + _find_resources(EditorFileSystem::get_singleton()->get_filesystem()); + _update_control(); +} + +void TextControlEditor::_update_fonts_menu() { + font_list->clear(); + font_list->add_item(TTR("[Theme Default]"), FONT_INFO_THEME_DEFAULT); + if (custom_font.is_valid()) { + font_list->add_item(TTR("[Custom Font]"), FONT_INFO_USER_CUSTOM); + } + + int id = FONT_INFO_ID; + for (Map<String, Map<String, String>>::Element *E = fonts.front(); E; E = E->next()) { + font_list->add_item(E->key(), id++); + } + + if (font_list->get_item_count() > 1) { + font_list->show(); + } else { + font_list->hide(); + } +} + +void TextControlEditor::_update_styles_menu() { + font_style_list->clear(); + if ((font_list->get_selected_id() >= FONT_INFO_ID)) { + const String &name = font_list->get_item_text(font_list->get_selected()); + for (Map<String, String>::Element *E = fonts[name].front(); E; E = E->next()) { + font_style_list->add_item(E->key()); + } + } else { + font_style_list->add_item("Default"); + } + + if (font_style_list->get_item_count() > 1) { + font_style_list->show(); + } else { + font_style_list->hide(); + } +} + +void TextControlEditor::_update_control() { + if (edited_control) { + // Get override names. + if (edited_control->is_class("RichTextLabel")) { + edited_color = "default_color"; + edited_font = "normal_font"; + edited_font_size = "normal_font_size"; + } else { + edited_color = "font_color"; + edited_font = "font"; + edited_font_size = "font_size"; + } + + // Get font override. + Ref<Font> font; + if (edited_control->has_theme_font_override(edited_font)) { + font = edited_control->get_theme_font(edited_font); + } + if (font.is_valid()) { + if (font->get_data_count() != 1) { + // Composite font, save it to "custom_font" to allow undoing font change. + custom_font = font; + _update_fonts_menu(); + font_list->select(FONT_INFO_USER_CUSTOM); + _update_styles_menu(); + font_style_list->select(0); + } else { + // Single face font, search for the font with matching name and style. + String name = font->get_data(0)->get_font_name(); + String style = font->get_data(0)->get_font_style_name(); + if (fonts.has(name) && fonts[name].has(style)) { + _update_fonts_menu(); + for (int i = 0; i < font_list->get_item_count(); i++) { + if (font_list->get_item_text(i) == name) { + font_list->select(i); + break; + } + } + _update_styles_menu(); + for (int i = 0; i < font_style_list->get_item_count(); i++) { + if (font_style_list->get_item_text(i) == style) { + font_style_list->select(i); + break; + } + } + } else { + // Unknown font, save it to "custom_font" to allow undoing font change. + custom_font = font; + _update_fonts_menu(); + font_list->select(FONT_INFO_USER_CUSTOM); + _update_styles_menu(); + font_style_list->select(0); + } + } + } else { + // No font override, select "Theme Default". + _update_fonts_menu(); + font_list->select(FONT_INFO_THEME_DEFAULT); + _update_styles_menu(); + font_style_list->select(0); + } + + // Get other theme overrides. + font_size_list->set_value(edited_control->get_theme_font_size(edited_font_size)); + outline_size_list->set_value(edited_control->get_theme_constant("outline_size")); + + font_color_picker->set_pick_color(edited_control->get_theme_color(edited_color)); + outline_color_picker->set_pick_color(edited_control->get_theme_color("font_outline_color")); + } +} + +void TextControlEditor::_font_selected(int p_id) { + _update_styles_menu(); + _set_font(); +} + +void TextControlEditor::_font_style_selected(int p_id) { + _set_font(); +} + +void TextControlEditor::_set_font() { + if (edited_control) { + if (font_list->get_selected_id() == FONT_INFO_THEME_DEFAULT) { + // Remove font override. + edited_control->remove_theme_font_override(edited_font); + return; + } else if (font_list->get_selected_id() == FONT_INFO_USER_CUSTOM) { + // Restore "custom_font". + edited_control->add_theme_font_override(edited_font, custom_font); + return; + } else { + // Load new font resource using selected name and style. + String name = font_list->get_item_text(font_list->get_selected()); + String sty = font_style_list->get_item_text(font_style_list->get_selected()); + if (sty.is_empty()) { + sty = "Default"; + } + if (fonts.has(name)) { + Ref<FontData> fd = ResourceLoader::load(fonts[name][sty]); + if (fd.is_valid()) { + Ref<Font> f; + f.instantiate(); + f->add_data(fd); + edited_control->add_theme_font_override(edited_font, f); + } + } + } + } +} + +void TextControlEditor::_font_size_selected(double p_size) { + if (edited_control) { + edited_control->add_theme_font_size_override(edited_font_size, p_size); + } +} + +void TextControlEditor::_outline_size_selected(double p_size) { + if (edited_control) { + edited_control->add_theme_constant_override("outline_size", p_size); + } +} + +void TextControlEditor::_font_color_changed(const Color &p_color) { + if (edited_control) { + edited_control->add_theme_color_override(edited_color, p_color); + } +} + +void TextControlEditor::_outline_color_changed(const Color &p_color) { + if (edited_control) { + edited_control->add_theme_color_override("font_outline_color", p_color); + } +} + +void TextControlEditor::_clear_formatting() { + if (edited_control) { + edited_control->begin_bulk_theme_override(); + edited_control->remove_theme_font_override(edited_font); + edited_control->remove_theme_font_size_override(edited_font_size); + edited_control->remove_theme_color_override(edited_color); + edited_control->remove_theme_color_override("font_outline_color"); + edited_control->remove_theme_constant_override("outline_size"); + edited_control->end_bulk_theme_override(); + _update_control(); + } +} + +void TextControlEditor::edit(Object *p_object) { + Control *ctrl = Object::cast_to<Control>(p_object); + if (!ctrl) { + edited_control = nullptr; + custom_font = Ref<Font>(); + } else { + edited_control = ctrl; + custom_font = Ref<Font>(); + _update_control(); + } +} + +bool TextControlEditor::handles(Object *p_object) const { + Control *ctrl = Object::cast_to<Control>(p_object); + if (!ctrl) { + return false; + } else { + bool valid = false; + ctrl->get("text", &valid); + return valid; + } +} + +TextControlEditor::TextControlEditor() { + add_child(memnew(VSeparator)); + + font_list = memnew(OptionButton); + font_list->set_flat(true); + font_list->set_tooltip(TTR("Font")); + add_child(font_list); + font_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_selected)); + + font_style_list = memnew(OptionButton); + font_style_list->set_flat(true); + font_style_list->set_tooltip(TTR("Font style")); + font_style_list->set_toggle_mode(true); + add_child(font_style_list); + font_style_list->connect("item_selected", callable_mp(this, &TextControlEditor::_font_style_selected)); + + font_size_list = memnew(SpinBox); + font_size_list->set_tooltip(TTR("Font Size")); + font_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2); + font_size_list->set_min(6); + font_size_list->set_step(1); + font_size_list->set_max(96); + font_size_list->get_line_edit()->set_flat(true); + add_child(font_size_list); + font_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_font_size_selected)); + + font_color_picker = memnew(ColorPickerButton); + font_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE); + font_color_picker->set_flat(true); + font_color_picker->set_tooltip(TTR("Text Color")); + add_child(font_color_picker); + font_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_font_color_changed)); + + add_child(memnew(VSeparator)); + + outline_size_list = memnew(SpinBox); + outline_size_list->set_tooltip(TTR("Outline Size")); + outline_size_list->get_line_edit()->add_theme_constant_override("minimum_character_width", 2); + outline_size_list->set_min(0); + outline_size_list->set_step(1); + outline_size_list->set_max(96); + outline_size_list->get_line_edit()->set_flat(true); + add_child(outline_size_list); + outline_size_list->connect("value_changed", callable_mp(this, &TextControlEditor::_outline_size_selected)); + + outline_color_picker = memnew(ColorPickerButton); + outline_color_picker->set_custom_minimum_size(Size2(20, 0) * EDSCALE); + outline_color_picker->set_flat(true); + outline_color_picker->set_tooltip(TTR("Outline Color")); + add_child(outline_color_picker); + outline_color_picker->connect("color_changed", callable_mp(this, &TextControlEditor::_outline_color_changed)); + + add_child(memnew(VSeparator)); + + clear_formatting = memnew(Button); + clear_formatting->set_flat(true); + clear_formatting->set_tooltip(TTR("Clear Formatting")); + add_child(clear_formatting); + clear_formatting->connect("pressed", callable_mp(this, &TextControlEditor::_clear_formatting)); +} + +/*************************************************************************/ + +void TextControlEditorPlugin::edit(Object *p_object) { + text_ctl_editor->edit(p_object); +} + +bool TextControlEditorPlugin::handles(Object *p_object) const { + return text_ctl_editor->handles(p_object); +} + +void TextControlEditorPlugin::make_visible(bool p_visible) { + if (p_visible) { + text_ctl_editor->show(); + } else { + text_ctl_editor->hide(); + text_ctl_editor->edit(nullptr); + } +} + +TextControlEditorPlugin::TextControlEditorPlugin(EditorNode *p_node) { + editor = p_node; + text_ctl_editor = memnew(TextControlEditor); + CanvasItemEditor::get_singleton()->add_control_to_menu_panel(text_ctl_editor); + + text_ctl_editor->hide(); +} diff --git a/editor/plugins/text_control_editor_plugin.h b/editor/plugins/text_control_editor_plugin.h new file mode 100644 index 0000000000..7f4aa3754c --- /dev/null +++ b/editor/plugins/text_control_editor_plugin.h @@ -0,0 +1,119 @@ +/*************************************************************************/ +/* text_control_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 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 TEXT_CONTROL_EDITOR_PLUGIN_H +#define TEXT_CONTROL_EDITOR_PLUGIN_H + +#include "canvas_item_editor_plugin.h" +#include "editor/editor_file_system.h" +#include "editor/editor_inspector.h" +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/gui/color_rect.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/popup_menu.h" + +/*************************************************************************/ + +class TextControlEditor : public HBoxContainer { + GDCLASS(TextControlEditor, HBoxContainer); + + enum FontInfoID { + FONT_INFO_THEME_DEFAULT = 0, + FONT_INFO_USER_CUSTOM = 1, + FONT_INFO_ID = 100, + }; + + Map<String, Map<String, String>> fonts; + + OptionButton *font_list = nullptr; + SpinBox *font_size_list = nullptr; + OptionButton *font_style_list = nullptr; + ColorPickerButton *font_color_picker = nullptr; + SpinBox *outline_size_list = nullptr; + ColorPickerButton *outline_color_picker = nullptr; + Button *clear_formatting = nullptr; + + Control *edited_control = nullptr; + String edited_color; + String edited_font; + String edited_font_size; + Ref<Font> custom_font; + +protected: + void _notification(int p_notification); + static void _bind_methods(){}; + + void _find_resources(EditorFileSystemDirectory *p_dir); + void _reload_fonts(const String &p_path); + + void _update_fonts_menu(); + void _update_styles_menu(); + void _update_control(); + + void _font_selected(int p_id); + void _font_style_selected(int p_id); + void _set_font(); + + void _font_size_selected(double p_size); + void _outline_size_selected(double p_size); + + void _font_color_changed(const Color &p_color); + void _outline_color_changed(const Color &p_color); + + void _clear_formatting(); + +public: + void edit(Object *p_object); + bool handles(Object *p_object) const; + + TextControlEditor(); +}; + +/*************************************************************************/ + +class TextControlEditorPlugin : public EditorPlugin { + GDCLASS(TextControlEditorPlugin, EditorPlugin); + + TextControlEditor *text_ctl_editor; + EditorNode *editor; + +public: + virtual String get_name() const override { return "TextControlFontEditor"; } + bool has_main_screen() const override { return false; } + virtual void edit(Object *p_object) override; + virtual bool handles(Object *p_object) const override; + virtual void make_visible(bool p_visible) override; + + TextControlEditorPlugin(EditorNode *p_node); +}; + +#endif // TEXT_CONTROL_EDITOR_PLUGIN_H diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 1fc7eb98e0..3b45f32927 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -65,7 +65,7 @@ void TextEditor::_load_theme_settings() { String TextEditor::get_name() { String name; - if (text_file->get_path().find("local://") == -1 && text_file->get_path().find("::") == -1) { + if (!text_file->is_built_in()) { name = text_file->get_path().get_file(); if (is_unsaved()) { if (text_file->get_path().is_empty()) { diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index bd1923f4ab..b4e394a1c0 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -173,7 +173,7 @@ Texture3DEditor::Texture3DEditor() { info->set_v_grow_direction(GROW_DIRECTION_BEGIN); info->add_theme_color_override("font_color", Color(1, 1, 1, 1)); info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5)); - info->add_theme_constant_override("shadow_as_outline", 1); + info->add_theme_constant_override("shadow_outline_size", 1); info->add_theme_constant_override("shadow_offset_x", 2); info->add_theme_constant_override("shadow_offset_y", 2); diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index b9ec6bf5ab..e25b0270b4 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -101,7 +101,7 @@ TexturePreview::TexturePreview(Ref<Texture2D> p_texture, bool p_show_metadata) { metadata_label->add_theme_color_override("font_outline_color", Color::named("black")); metadata_label->add_theme_constant_override("outline_size", 2 * EDSCALE); - metadata_label->add_theme_constant_override("shadow_as_outline", 1); + metadata_label->add_theme_constant_override("shadow_outline_size", 1); metadata_label->set_h_size_flags(Control::SIZE_SHRINK_END); metadata_label->set_v_size_flags(Control::SIZE_SHRINK_END); diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index 424e018a47..ee62138d12 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -249,7 +249,7 @@ TextureLayeredEditor::TextureLayeredEditor() { info->set_v_grow_direction(GROW_DIRECTION_BEGIN); info->add_theme_color_override("font_color", Color(1, 1, 1, 1)); info->add_theme_color_override("font_shadow_color", Color(0, 0, 0, 0.5)); - info->add_theme_constant_override("shadow_as_outline", 1); + info->add_theme_constant_override("shadow_outline_size", 1); info->add_theme_constant_override("shadow_offset_x", 2); info->add_theme_constant_override("shadow_offset_y", 2); diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index f1918073fb..47dfc57b0f 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -47,8 +47,12 @@ TilesEditorPlugin *TilesEditorPlugin::singleton = nullptr; -void TilesEditorPlugin::_pattern_preview_done(const Variant &p_udata) { - pattern_preview_done.set(); +void TilesEditorPlugin::_preview_frame_started() { + RS::get_singleton()->request_frame_drawn_callback(callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_pattern_preview_done)); +} + +void TilesEditorPlugin::_pattern_preview_done() { + pattern_preview_done.post(); } void TilesEditorPlugin::_thread_func(void *ud) { @@ -112,12 +116,9 @@ void TilesEditorPlugin::_thread() { // Add the viewport at the lasst moment to avoid rendering too early. EditorNode::get_singleton()->add_child(viewport); - pattern_preview_done.clear(); - RS::get_singleton()->request_frame_drawn_callback(const_cast<TilesEditorPlugin *>(this), "_pattern_preview_done", Variant()); + RS::get_singleton()->connect(SNAME("frame_pre_draw"), callable_mp(const_cast<TilesEditorPlugin *>(this), &TilesEditorPlugin::_preview_frame_started), Vector<Variant>(), Object::CONNECT_ONESHOT); - while (!pattern_preview_done.is_set()) { - OS::get_singleton()->delay_usec(10); - } + pattern_preview_done.wait(); Ref<Image> image = viewport->get_texture()->get_image(); Ref<ImageTexture> image_texture; @@ -274,10 +275,6 @@ bool TilesEditorPlugin::handles(Object *p_object) const { return p_object->is_class("TileMap") || p_object->is_class("TileSet"); } -void TilesEditorPlugin::_bind_methods() { - ClassDB::bind_method(D_METHOD("_pattern_preview_done", "pattern"), &TilesEditorPlugin::_pattern_preview_done); -} - TilesEditorPlugin::TilesEditorPlugin(EditorNode *p_node) { set_process_internal(true); diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h index dd52bdc31a..33493040f6 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.h +++ b/editor/plugins/tiles/tiles_editor_plugin.h @@ -77,14 +77,14 @@ private: Thread pattern_preview_thread; SafeFlag pattern_thread_exit; SafeFlag pattern_thread_exited; - mutable SafeFlag pattern_preview_done; - void _pattern_preview_done(const Variant &p_udata); + Semaphore pattern_preview_done; + void _preview_frame_started(); + void _pattern_preview_done(); static void _thread_func(void *ud); void _thread(); protected: void _notification(int p_what); - static void _bind_methods(); public: _FORCE_INLINE_ static TilesEditorPlugin *get_singleton() { return singleton; } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index c06eafae50..10a9b2bb10 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -4977,7 +4977,7 @@ public: } } - void setup(Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, Ref<VisualShaderNode> p_node) { + void setup(Ref<Resource> p_parent_resource, Vector<EditorProperty *> p_properties, const Vector<StringName> &p_names, const Map<StringName, String> &p_overrided_names, Ref<VisualShaderNode> p_node) { parent_resource = p_parent_resource; updating = false; node = p_node; @@ -4993,7 +4993,11 @@ public: Label *prop_name = memnew(Label); String prop_name_str = p_names[i]; - prop_name_str = prop_name_str.capitalize() + ":"; + if (p_overrided_names.has(p_names[i])) { + prop_name_str = p_overrided_names[p_names[i]] + ":"; + } else { + prop_name_str = prop_name_str.capitalize() + ":"; + } prop_name->set_text(prop_name_str); prop_name->set_visible(false); hbox->add_child(prop_name); @@ -5085,7 +5089,7 @@ Control *VisualShaderNodePluginDefault::create_editor(const Ref<Resource> &p_par properties.push_back(pinfo[i].name); } VisualShaderNodePluginDefaultEditor *editor = memnew(VisualShaderNodePluginDefaultEditor); - editor->setup(p_parent_resource, editors, properties, p_node); + editor->setup(p_parent_resource, editors, properties, p_node->get_editable_properties_names(), p_node); return editor; } diff --git a/editor/property_editor.cpp b/editor/property_editor.cpp index db560af657..62c5cc5cc1 100644 --- a/editor/property_editor.cpp +++ b/editor/property_editor.cpp @@ -1671,7 +1671,7 @@ void CustomPropertyEditor::_focus_exit() { } void CustomPropertyEditor::config_action_buttons(const List<String> &p_strings) { - Ref<StyleBox> sb = action_buttons[0]->get_theme_stylebox(SNAME("panel")); + Ref<StyleBox> sb = action_buttons[0]->get_theme_stylebox(SNAME("button")); int margin_top = sb->get_margin(SIDE_TOP); int margin_left = sb->get_margin(SIDE_LEFT); int margin_bottom = sb->get_margin(SIDE_BOTTOM); @@ -1804,26 +1804,18 @@ CustomPropertyEditor::CustomPropertyEditor() { } text_edit = memnew(TextEdit); - add_child(text_edit); + value_vbox->add_child(text_edit); text_edit->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); + text_edit->set_v_size_flags(Control::SIZE_EXPAND_FILL); text_edit->set_offset(SIDE_BOTTOM, -30); text_edit->hide(); text_edit->connect("text_changed", callable_mp(this, &CustomPropertyEditor::_text_edit_changed)); - for (int i = 0; i < MAX_ACTION_BUTTONS; i++) { - action_buttons[i] = memnew(Button); - action_buttons[i]->hide(); - add_child(action_buttons[i]); - Vector<Variant> binds; - binds.push_back(i); - action_buttons[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed), binds); - } - color_picker = nullptr; file = memnew(EditorFileDialog); - add_child(file); + value_vbox->add_child(file); file->hide(); file->connect("file_selected", callable_mp(this, &CustomPropertyEditor::_file_selected)); @@ -1831,46 +1823,58 @@ CustomPropertyEditor::CustomPropertyEditor() { error = memnew(ConfirmationDialog); error->set_title(TTR("Error!")); - add_child(error); + value_vbox->add_child(error); scene_tree = memnew(SceneTreeDialog); - add_child(scene_tree); + value_vbox->add_child(scene_tree); scene_tree->connect("selected", callable_mp(this, &CustomPropertyEditor::_node_path_selected)); scene_tree->get_scene_tree()->set_show_enabled_subscene(true); texture_preview = memnew(TextureRect); - add_child(texture_preview); + value_vbox->add_child(texture_preview); texture_preview->hide(); easing_draw = memnew(Control); - add_child(easing_draw); + value_vbox->add_child(easing_draw); easing_draw->hide(); easing_draw->connect("draw", callable_mp(this, &CustomPropertyEditor::_draw_easing)); easing_draw->connect("gui_input", callable_mp(this, &CustomPropertyEditor::_drag_easing)); easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE); type_button = memnew(MenuButton); - add_child(type_button); + value_vbox->add_child(type_button); type_button->hide(); type_button->get_popup()->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_type_create_selected)); menu = memnew(PopupMenu); // menu->set_pass_on_modal_close_click(false); - add_child(menu); + value_vbox->add_child(menu); menu->connect("id_pressed", callable_mp(this, &CustomPropertyEditor::_menu_option)); evaluator = nullptr; spinbox = memnew(SpinBox); - add_child(spinbox); + value_vbox->add_child(spinbox); spinbox->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); spinbox->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified)); slider = memnew(HSlider); - add_child(slider); + value_vbox->add_child(slider); slider->set_anchors_and_offsets_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 5); slider->connect("value_changed", callable_mp(this, &CustomPropertyEditor::_range_modified)); + action_hboxes = memnew(HBoxContainer); + action_hboxes->set_alignment(BoxContainer::ALIGN_CENTER); + value_vbox->add_child(action_hboxes); + for (int i = 0; i < MAX_ACTION_BUTTONS; i++) { + action_buttons[i] = memnew(Button); + action_buttons[i]->hide(); + action_hboxes->add_child(action_buttons[i]); + Vector<Variant> binds; + binds.push_back(i); + action_buttons[i]->connect("pressed", callable_mp(this, &CustomPropertyEditor::_action_pressed), binds); + } + create_dialog = nullptr; property_select = nullptr; } diff --git a/editor/property_editor.h b/editor/property_editor.h index 23771b7494..2565c6ee27 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -110,6 +110,7 @@ class CustomPropertyEditor : public PopupPanel { int focused_value_editor; Label *value_label[MAX_VALUE_EDITORS]; HScrollBar *scroll[4]; + HBoxContainer *action_hboxes; Button *action_buttons[MAX_ACTION_BUTTONS]; MenuButton *type_button; Vector<String> inheritors_array; diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 2792c193d9..f5b70504fa 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -461,7 +461,7 @@ String RenameDialog::_substitute(const String &subject, const Node *node, int co void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *p_file, int p_line, const char *p_error, const char *p_errorexp, bool p_editor_notify, ErrorHandlerType p_type) { RenameDialog *self = (RenameDialog *)p_self; - String source_file(p_file); + String source_file = String::utf8(p_file); // Only show first error that is related to "regex" if (self->has_errors || source_file.find("regex") < 0) { @@ -470,9 +470,9 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char * String err_str; if (p_errorexp && p_errorexp[0]) { - err_str = p_errorexp; + err_str = String::utf8(p_errorexp); } else { - err_str = p_error; + err_str = String::utf8(p_error); } self->has_errors = true; diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 336a0e4c37..921befbb6b 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -47,6 +47,7 @@ #include "editor/plugins/script_editor_plugin.h" #include "editor/shader_create_dialog.h" #include "scene/main/window.h" +#include "scene/property_utils.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" #include "servers/rendering_server.h" @@ -2153,7 +2154,7 @@ void SceneTreeDock::_do_create(Node *p_parent) { editor_data->get_undo_redo().create_action(TTR("Create Node")); if (edited_scene) { - editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child); + editor_data->get_undo_redo().add_do_method(p_parent, "add_child", child, true); editor_data->get_undo_redo().add_do_method(child, "set_owner", edited_scene); editor_data->get_undo_redo().add_do_method(editor_selection, "clear"); editor_data->get_undo_redo().add_do_method(editor_selection, "add_node", child); @@ -3132,7 +3133,9 @@ void SceneTreeDock::_clear_clipboard() { void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) { List<PropertyInfo> props; p_node->get_property_list(&props); - bool is_instantiated = EditorPropertyRevert::may_node_be_in_instance(p_node); + + Vector<SceneState::PackState> states_stack; + bool states_stack_ready = false; for (const PropertyInfo &E : props) { if (!(E.usage & PROPERTY_USAGE_STORAGE)) { @@ -3143,16 +3146,17 @@ void SceneTreeDock::_create_remap_for_node(Node *p_node, Map<RES, RES> &r_remap) if (v.is_ref()) { RES res = v; if (res.is_valid()) { - if (is_instantiated) { - Variant orig; - if (EditorPropertyRevert::get_instantiated_node_original_property(p_node, E.name, orig)) { - if (!EditorPropertyRevert::is_node_property_different(p_node, v, orig)) { - continue; - } - } + if (!states_stack_ready) { + states_stack = PropertyUtils::get_node_states_stack(p_node); + states_stack_ready = true; + } + + Variant orig = PropertyUtils::get_property_default_value(p_node, E.name, &states_stack); + if (!PropertyUtils::is_property_value_different(v, orig)) { + continue; } - if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) { + if (res->is_built_in() && !r_remap.has(res)) { _create_remap_for_resource(res, r_remap); } } @@ -3179,7 +3183,7 @@ void SceneTreeDock::_create_remap_for_resource(RES p_resource, Map<RES, RES> &r_ if (v.is_ref()) { RES res = v; if (res.is_valid()) { - if ((res->get_path() == "" || res->get_path().find("::") > -1) && !r_remap.has(res)) { + if (res->is_built_in() && !r_remap.has(res)) { _create_remap_for_resource(res, r_remap); } } |