diff options
Diffstat (limited to 'editor')
153 files changed, 2275 insertions, 1167 deletions
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index a7a07a41ac..530708f3e5 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/gui/view_panner.h" #include "scene/resources/text_line.h" @@ -1591,7 +1592,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { } Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Duplicate Keys")); + undo_redo->create_action(TTR("Animation Duplicate Keys")); List<Pair<int, real_t>> new_selection_values; @@ -1637,7 +1638,7 @@ void AnimationBezierTrackEdit::duplicate_selection() { void AnimationBezierTrackEdit::delete_selection() { if (selection.size()) { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Delete Keys")); + undo_redo->create_action(TTR("Animation Delete Keys")); for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 9587a84e18..2ee06a0dbd 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -35,10 +35,13 @@ #include "editor/animation_bezier_editor.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "scene/animation/animation_player.h" #include "scene/animation/tween.h" +#include "scene/gui/grid_container.h" #include "scene/gui/separator.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" @@ -134,7 +137,7 @@ public: setting = true; Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Change Keyframe Time"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS); Variant val = animation->track_get_key_value(track, key); float trans = animation->track_get_key_transition(track, key); @@ -162,7 +165,7 @@ public: float prev_val = animation->track_get_key_transition(track, key); setting = true; Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Change Transition"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS); undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); undo_redo->add_do_method(this, "_update_obj", animation); @@ -218,7 +221,7 @@ public: } setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); Variant prev = animation->track_get_key_value(track, key); undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev); @@ -278,9 +281,9 @@ public: } if (mergeable) { - undo_redo->create_action(TTR("Anim Change Call"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Call"), UndoRedo::MERGE_ENDS); } else { - undo_redo->create_action(TTR("Anim Change Call")); + undo_redo->create_action(TTR("Animation Change Call")); } setting = true; @@ -301,7 +304,7 @@ public: const Variant &value = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); float prev = animation->bezier_track_get_key_value(track, key); undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev); @@ -317,7 +320,7 @@ public: const Variant &value = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev); @@ -333,7 +336,7 @@ public: const Variant &value = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value); undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev); @@ -349,7 +352,7 @@ public: const Variant &value = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); int prev = animation->bezier_track_get_key_handle_mode(track, key); undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); undo_redo->add_undo_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, prev); @@ -366,7 +369,7 @@ public: Ref<AudioStream> stream = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); Ref<Resource> prev = animation->audio_track_get_key_stream(track, key); undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream); undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev); @@ -382,7 +385,7 @@ public: float value = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); float prev = animation->audio_track_get_key_start_offset(track, key); undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value); undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev); @@ -398,7 +401,7 @@ public: float value = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); float prev = animation->audio_track_get_key_end_offset(track, key); undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value); undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev); @@ -415,7 +418,7 @@ public: StringName anim_name = p_value; setting = true; - undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Change Keyframe Value"), UndoRedo::MERGE_ENDS); StringName prev = animation->animation_track_get_key_animation(track, key); undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name); undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev); @@ -815,7 +818,7 @@ public: Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Time"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Time"), UndoRedo::MERGE_ENDS); } Variant val = animation->track_get_key_value(track, key); @@ -840,7 +843,7 @@ public: Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Transition"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS); } undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val); undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val); @@ -870,7 +873,7 @@ public: } setting = true; - undo_redo->create_action(vformat(TTR("Anim Multi Change %s"), chan)); + undo_redo->create_action(vformat(TTR("Animation Multi Change %s"), chan)); } undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); @@ -887,7 +890,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Variant prev = animation->track_get_key_value(track, key); undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value); @@ -945,9 +948,9 @@ public: if (!setting) { if (mergeable) { - undo_redo->create_action(TTR("Anim Multi Change Call"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Call"), UndoRedo::MERGE_ENDS); } else { - undo_redo->create_action(TTR("Anim Multi Change Call")); + undo_redo->create_action(TTR("Animation Multi Change Call")); } setting = true; @@ -963,7 +966,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } float prev = animation->bezier_track_get_key_value(track, key); undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value); @@ -974,7 +977,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Vector2 prev = animation->bezier_track_get_key_in_handle(track, key); undo_redo->add_do_method(this, "_bezier_track_set_key_in_handle", track, key, value); @@ -985,7 +988,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Vector2 prev = animation->bezier_track_get_key_out_handle(track, key); undo_redo->add_do_method(this, "_bezier_track_set_key_out_handle", track, key, value); @@ -996,7 +999,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } int prev = animation->bezier_track_get_key_handle_mode(track, key); undo_redo->add_do_method(this, "_bezier_track_set_key_handle_mode", animation.ptr(), track, key, value); @@ -1010,7 +1013,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } Ref<Resource> prev = animation->audio_track_get_key_stream(track, key); undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream); @@ -1021,7 +1024,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } float prev = animation->audio_track_get_key_start_offset(track, key); undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value); @@ -1032,7 +1035,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } float prev = animation->audio_track_get_key_end_offset(track, key); undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value); @@ -1046,7 +1049,7 @@ public: if (!setting) { setting = true; - undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); + undo_redo->create_action(TTR("Animation Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS); } StringName prev = animation->animation_track_get_key_animation(track, key); undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name); @@ -1751,7 +1754,9 @@ void AnimationTimelineEdit::update_values() { length->set_step(1); length->set_tooltip_text(TTR("Animation length (frames)")); time_icon->set_tooltip_text(TTR("Animation length (frames)")); - track_edit->editor->_update_key_edit(); + if (track_edit) { + track_edit->editor->_update_key_edit(); + } } else { length->set_value(animation->get_length()); length->set_step(0.001); @@ -2129,10 +2134,9 @@ void AnimationTrackEdit::_notification(int p_what) { get_theme_icon(SNAME("InterpLinearAngle"), SNAME("EditorIcons")), get_theme_icon(SNAME("InterpCubicAngle"), SNAME("EditorIcons")), }; - Ref<Texture2D> cont_icon[4] = { + Ref<Texture2D> cont_icon[3] = { get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), - get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")), get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")) }; @@ -2824,7 +2828,6 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) { menu->clear(); menu->add_icon_item(get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS); menu->add_icon_item(get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")), TTR("Discrete"), MENU_CALL_MODE_DISCRETE); - menu->add_icon_item(get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")), TTR("Trigger"), MENU_CALL_MODE_TRIGGER); menu->add_icon_item(get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons")), TTR("Capture"), MENU_CALL_MODE_CAPTURE); menu->reset_size(); @@ -3189,7 +3192,6 @@ void AnimationTrackEdit::_menu_selected(int p_index) { switch (p_index) { case MENU_CALL_MODE_CONTINUOUS: case MENU_CALL_MODE_DISCRETE: - case MENU_CALL_MODE_TRIGGER: case MENU_CALL_MODE_CAPTURE: { Animation::UpdateMode update_mode = Animation::UpdateMode(p_index); Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); @@ -3456,7 +3458,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_re _update_tracks(); if (animation.is_valid()) { - animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed), CONNECT_DEFERRED); + animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); hscroll->show(); edit->set_disabled(read_only); @@ -3812,7 +3814,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) { void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_beziers) { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Insert")); + undo_redo->create_action(TTR("Animation Insert Key")); Ref<Animation> reset_anim; if (p_reset_wanted) { @@ -3849,7 +3851,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_ } // Let's build a node path. - String path = root->get_path_to(p_node); + String path = root->get_path_to(p_node, true); if (!p_sub.is_empty()) { path += ":" + p_sub; } @@ -3889,7 +3891,7 @@ bool AnimationTrackEditor::has_track(Node3D *p_node, const String &p_sub, const } // Let's build a node path. - String path = root->get_path_to(p_node); + String path = root->get_path_to(p_node, true); if (!p_sub.is_empty()) { path += ":" + p_sub; } @@ -3937,11 +3939,10 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) { ERR_FAIL_COND(!root); - // Let's build a node path. + // Let's build a node path. Node *node = p_node; - - String path = root->get_path_to(node); + String path = root->get_path_to(node, true); if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") { if (node == AnimationPlayerEditor::get_singleton()->get_player()) { @@ -4035,14 +4036,13 @@ void AnimationTrackEditor::insert_value_key(const String &p_property, const Vari EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history(); ERR_FAIL_COND(!root); - // Let's build a node path. ERR_FAIL_COND(history->get_path_size() == 0); Object *obj = ObjectDB::get_instance(history->get_path_object(0)); ERR_FAIL_COND(!Object::cast_to<Node>(obj)); + // Let's build a node path. Node *node = Object::cast_to<Node>(obj); - - String path = root->get_path_to(node); + String path = root->get_path_to(node, true); if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") { if (node == AnimationPlayerEditor::get_singleton()->get_player()) { @@ -4153,7 +4153,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() { void AnimationTrackEditor::_confirm_insert_list() { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Create & Insert")); + undo_redo->create_action(TTR("Animation Insert Key")); bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed(); Ref<Animation> reset_anim; @@ -4319,10 +4319,6 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD h.type == Variant::TRANSFORM3D) { update_mode = Animation::UPDATE_CONTINUOUS; } - - if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) { - update_mode = Animation::UPDATE_TRIGGER; - } } } @@ -4344,7 +4340,6 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD } } created = true; - undo_redo->create_action(TTR("Anim Insert Track & Key")); p_id.track_idx = p_next_tracks.normal; @@ -4353,9 +4348,6 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD if (p_id.type == Animation::TYPE_VALUE) { undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", p_id.track_idx, update_mode); } - - } else { - undo_redo->create_action(TTR("Anim Insert Key")); } float time = timeline->get_play_position(); @@ -4426,8 +4418,6 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD } } - undo_redo->commit_action(); - return p_next_tracks; } @@ -4657,19 +4647,19 @@ void AnimationTrackEditor::_animation_changed() { } if (key_edit) { - _update_key_edit(); - } - - if (key_edit && key_edit->setting) { - // If editing a key, just redraw the edited track, makes refresh less costly. - if (key_edit->track < track_edits.size()) { - if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) { - bezier_edit->queue_redraw(); - } else { - track_edits[key_edit->track]->queue_redraw(); + if (key_edit->setting) { + // If editing a key, just redraw the edited track, makes refresh less costly. + if (key_edit->track < track_edits.size()) { + if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER) { + bezier_edit->queue_redraw(); + } else { + track_edits[key_edit->track]->queue_redraw(); + } } + return; + } else { + _update_key_edit(); } - return; } animation_changing_awaiting_update = true; @@ -4826,7 +4816,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) { ERR_FAIL_COND(!root); Node *node = get_node(p_path); ERR_FAIL_COND(!node); - NodePath path_to = root->get_path_to(node); + NodePath path_to = root->get_path_to(node, true); if (adding_track_type == Animation::TYPE_BLEND_SHAPE && !node->is_class("MeshInstance3D")) { EditorNode::get_singleton()->show_warning(TTR("Blend Shape tracks only apply to MeshInstance3D nodes.")); @@ -4950,10 +4940,6 @@ void AnimationTrackEditor::_new_track_property_selected(String p_name) { h.type == Variant::TRANSFORM3D) { update_mode = Animation::UPDATE_CONTINUOUS; } - - if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) { - update_mode = Animation::UPDATE_TRIGGER; - } } undo_redo->create_action(TTR("Add Track")); @@ -5289,7 +5275,12 @@ void AnimationTrackEditor::_update_key_edit() { key_edit->track = selection.front()->key().track; key_edit->use_fps = timeline->is_using_fps(); - float ofs = animation->track_get_key_time(key_edit->track, selection.front()->key().key); + int key_id = selection.front()->key().key; + if (key_id >= animation->track_get_key_count(key_edit->track)) { + _clear_key_edit(); + return; // Probably in the process of rearranging the keys. + } + float ofs = animation->track_get_key_time(key_edit->track, key_id); key_edit->key_ofs = ofs; key_edit->root_path = root; @@ -5317,6 +5308,11 @@ void AnimationTrackEditor::_update_key_edit() { base_map[track] = NodePath(); } + int key_id = E.key.key; + if (key_id >= animation->track_get_key_count(track)) { + _clear_key_edit(); + return; // Probably in the process of rearranging the keys. + } key_ofs_map[track].push_back(animation->track_get_key_time(track, E.key.key)); } multi_key_edit->key_ofs_map = key_ofs_map; @@ -5352,11 +5348,12 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t ki.pos = p_pos; selection.insert(sk, ki); + _update_key_edit(); } void AnimationTrackEditor::_move_selection_commit() { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Move Keys")); + undo_redo->create_action(TTR("Animation Move Keys")); List<_AnimMoveRestore> to_restore; @@ -5428,7 +5425,6 @@ void AnimationTrackEditor::_move_selection_commit() { undo_redo->add_do_method(this, "_redraw_tracks"); undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); - _update_key_edit(); } void AnimationTrackEditor::_move_selection_cancel() { @@ -5609,7 +5605,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { int start_track = transpose ? _get_track_selected() : top_track; Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Duplicate Keys")); + undo_redo->create_action(TTR("Animation Duplicate Keys")); List<Pair<int, float>> new_selection_values; @@ -5659,7 +5655,6 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) { undo_redo->add_do_method(this, "_redraw_tracks"); undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); - _update_key_edit(); } } @@ -5907,12 +5902,10 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } float s = scale->get_value(); - if (s == 0) { - ERR_PRINT("Can't scale to 0"); - } + ERR_FAIL_COND_MSG(s == 0, "Can't scale to 0."); Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Scale Keys")); + undo_redo->create_action(TTR("Animation Scale Keys")); List<_AnimMoveRestore> to_restore; @@ -5985,8 +5978,6 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { undo_redo->add_do_method(this, "_redraw_tracks"); undo_redo->add_undo_method(this, "_redraw_tracks"); undo_redo->commit_action(); - _update_key_edit(); - } break; case EDIT_EASE_SELECTION: { @@ -6101,7 +6092,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { } break; case EDIT_ADD_RESET_KEY: { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Add RESET Keys")); + undo_redo->create_action(TTR("Animation Add RESET Keys")); Ref<Animation> reset = _create_and_get_reset_animation(); int reset_tracks = reset->get_track_count(); @@ -6162,7 +6153,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) { if (selection.size()) { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); - undo_redo->create_action(TTR("Anim Delete Keys")); + undo_redo->create_action(TTR("Animation Delete Keys")); for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) { undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key); diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index e7d73cc8dd..4b50424f39 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -138,7 +138,6 @@ class AnimationTrackEdit : public Control { enum { MENU_CALL_MODE_CONTINUOUS, MENU_CALL_MODE_DISCRETE, - MENU_CALL_MODE_TRIGGER, MENU_CALL_MODE_CAPTURE, MENU_INTERPOLATION_NEAREST, MENU_INTERPOLATION_LINEAR, @@ -427,7 +426,6 @@ class AnimationTrackEditor : public VBoxContainer { AnimationTrackKeyEdit *key_edit = nullptr; AnimationMultiTrackKeyEdit *multi_key_edit = nullptr; void _update_key_edit(); - void _clear_key_edit(); Control *box_selection = nullptr; diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp index a5f6f449a6..704935e163 100644 --- a/editor/animation_track_editor_plugins.cpp +++ b/editor/animation_track_editor_plugins.cpp @@ -857,18 +857,14 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int float start_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), p_index); float end_ofs = get_animation()->audio_track_get_key_end_offset(get_track(), p_index); + int px_offset = 0; if (len_resizing && p_index == len_resizing_index) { - float ofs_local = -len_resizing_rel / get_timeline()->get_zoom_scale(); + float ofs_local = len_resizing_rel / get_timeline()->get_zoom_scale(); if (len_resizing_start) { start_ofs += ofs_local; - if (start_ofs < 0) { - start_ofs = 0; - } + px_offset = ofs_local * p_pixels_sec; } else { - end_ofs += ofs_local; - if (end_ofs < 0) { - end_ofs = 0; - } + end_ofs -= ofs_local; } } @@ -897,8 +893,8 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int int pixel_len = len * p_pixels_sec; - int pixel_begin = p_x; - int pixel_end = p_x + pixel_len; + int pixel_begin = px_offset + p_x; + int pixel_end = px_offset + p_x + pixel_len; if (pixel_end < p_clip_left) { return; @@ -1061,9 +1057,6 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { len -= end_ofs; len -= start_ofs; - if (len <= 0.001) { - len = 0.001; - } if (get_animation()->track_get_key_count(get_track()) > i + 1) { len = MIN(len, get_animation()->track_get_key_time(get_track(), i + 1) - get_animation()->track_get_key_time(get_track(), i)); @@ -1078,6 +1071,13 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { int end = ofs + len * get_timeline()->get_zoom_scale(); if (end >= get_timeline()->get_name_limit() && end <= get_size().width - get_timeline()->get_buttons_width() && ABS(mm->get_position().x - end) < 5 * EDSCALE) { + len_resizing_start = false; + use_hsize_cursor = true; + len_resizing_index = i; + } + + if (ofs >= get_timeline()->get_name_limit() && ofs <= get_size().width - get_timeline()->get_buttons_width() && ABS(mm->get_position().x - ofs) < 5 * EDSCALE) { + len_resizing_start = true; use_hsize_cursor = true; len_resizing_index = i; } @@ -1086,8 +1086,25 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { } if (len_resizing && mm.is_valid()) { + // Rezising index is some. len_resizing_rel += mm->get_relative().x; - len_resizing_start = mm->is_shift_pressed(); + float ofs_local = len_resizing_rel / get_timeline()->get_zoom_scale(); + float prev_ofs_start = get_animation()->audio_track_get_key_start_offset(get_track(), len_resizing_index); + float prev_ofs_end = get_animation()->audio_track_get_key_end_offset(get_track(), len_resizing_index); + Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), len_resizing_index); + float len = stream->get_length(); + if (len == 0) { + Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream); + float preview_len = preview->get_length(); + len = preview_len; + } + + if (len_resizing_start) { + len_resizing_rel = CLAMP(ofs_local, -prev_ofs_start, len - prev_ofs_end - prev_ofs_start) * get_timeline()->get_zoom_scale(); + } else { + len_resizing_rel = CLAMP(ofs_local, -(len - prev_ofs_end - prev_ofs_start), prev_ofs_end) * get_timeline()->get_zoom_scale(); + } + queue_redraw(); accept_event(); return; @@ -1096,7 +1113,11 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && over_drag_position) { len_resizing = true; - len_resizing_start = mb->is_shift_pressed(); + // In case if resizing index is not set yet reset the flag. + if (len_resizing_index < 0) { + len_resizing = false; + return; + } len_resizing_from_px = mb->get_position().x; len_resizing_rel = 0; queue_redraw(); @@ -1106,23 +1127,42 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - float ofs_local = -len_resizing_rel / get_timeline()->get_zoom_scale(); + if (len_resizing_rel == 0 || len_resizing_index < 0) { + len_resizing = false; + return; + } + if (len_resizing_start) { + float ofs_local = len_resizing_rel / get_timeline()->get_zoom_scale(); float prev_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), len_resizing_index); - undo_redo->create_action(TTR("Change Audio Track Clip Start Offset")); - undo_redo->add_do_method(get_animation().ptr(), "audio_track_set_key_start_offset", get_track(), len_resizing_index, prev_ofs + ofs_local); - undo_redo->add_undo_method(get_animation().ptr(), "audio_track_set_key_start_offset", get_track(), len_resizing_index, prev_ofs); - undo_redo->commit_action(); + float prev_time = get_animation()->track_get_key_time(get_track(), len_resizing_index); + float new_ofs = prev_ofs + ofs_local; + float new_time = prev_time + ofs_local; + if (prev_time != new_time) { + undo_redo->create_action(TTR("Change Audio Track Clip Start Offset")); + + undo_redo->add_do_method(get_animation().ptr(), "track_set_key_time", get_track(), len_resizing_index, new_time); + undo_redo->add_undo_method(get_animation().ptr(), "track_set_key_time", get_track(), len_resizing_index, prev_time); + + undo_redo->add_do_method(get_animation().ptr(), "audio_track_set_key_start_offset", get_track(), len_resizing_index, new_ofs); + undo_redo->add_undo_method(get_animation().ptr(), "audio_track_set_key_start_offset", get_track(), len_resizing_index, prev_ofs); + undo_redo->commit_action(); + } } else { + float ofs_local = -len_resizing_rel / get_timeline()->get_zoom_scale(); float prev_ofs = get_animation()->audio_track_get_key_end_offset(get_track(), len_resizing_index); - undo_redo->create_action(TTR("Change Audio Track Clip End Offset")); - undo_redo->add_do_method(get_animation().ptr(), "audio_track_set_key_end_offset", get_track(), len_resizing_index, prev_ofs + ofs_local); - undo_redo->add_undo_method(get_animation().ptr(), "audio_track_set_key_end_offset", get_track(), len_resizing_index, prev_ofs); - undo_redo->commit_action(); + float new_ofs = prev_ofs + ofs_local; + if (prev_ofs != new_ofs) { + undo_redo->create_action(TTR("Change Audio Track Clip End Offset")); + undo_redo->add_do_method(get_animation().ptr(), "audio_track_set_key_end_offset", get_track(), len_resizing_index, new_ofs); + undo_redo->add_undo_method(get_animation().ptr(), "audio_track_set_key_end_offset", get_track(), len_resizing_index, prev_ofs); + undo_redo->commit_action(); + } } len_resizing_index = -1; + len_resizing = false; queue_redraw(); accept_event(); return; diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index e907d5a281..7ae0db7b48 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -33,6 +33,7 @@ #include "core/input/input.h" #include "core/os/keyboard.h" #include "core/string/string_builder.h" +#include "core/templates/pair.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/plugins/script_editor_plugin.h" @@ -872,6 +873,10 @@ void CodeTextEditor::_reset_zoom() { } void CodeTextEditor::_line_col_changed() { + if (!code_complete_timer->is_stopped() && code_complete_timer_line != text_editor->get_caret_line()) { + code_complete_timer->stop(); + } + String line = text_editor->get_line(text_editor->get_caret_line()); int positional_column = 0; @@ -901,6 +906,7 @@ void CodeTextEditor::_line_col_changed() { void CodeTextEditor::_text_changed() { if (text_editor->is_insert_text_operation()) { + code_complete_timer_line = text_editor->get_caret_line(); code_complete_timer->start(); } @@ -1290,90 +1296,98 @@ void CodeTextEditor::convert_case(CaseStyle p_case) { void CodeTextEditor::move_lines_up() { text_editor->begin_complex_operation(); - Vector<int> carets_to_remove; - Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order(); + + // Lists of carets representing each group + Vector<Vector<int>> caret_groups; + Vector<Pair<int, int>> group_borders; + + // Search for groups of carets and their selections residing on the same lines for (int i = 0; i < caret_edit_order.size(); i++) { int c = caret_edit_order[i]; - int cl = text_editor->get_caret_line(c); - bool swaped_caret = false; - for (int j = i + 1; j < caret_edit_order.size(); j++) { - if (text_editor->has_selection(caret_edit_order[j])) { - if (text_editor->get_selection_from_line() == cl) { - carets_to_remove.push_back(caret_edit_order[j]); - continue; - } + Vector<int> new_group{ c }; + Pair<int, int> group_border; + if (text_editor->has_selection(c)) { + group_border.first = text_editor->get_selection_from_line(c); + group_border.second = text_editor->get_selection_to_line(c); + } else { + group_border.first = text_editor->get_caret_line(c); + group_border.second = text_editor->get_caret_line(c); + } - if (text_editor->get_selection_to_line() == cl) { - if (text_editor->has_selection(c)) { - if (text_editor->get_selection_to_line(c) != cl) { - text_editor->select(cl + 1, 0, text_editor->get_selection_to_line(c), text_editor->get_selection_to_column(c), c); - break; - } - } + for (int j = i; j < caret_edit_order.size() - 1; j++) { + int c_current = caret_edit_order[j]; + int c_next = caret_edit_order[j + 1]; - carets_to_remove.push_back(c); - i = j - 1; - swaped_caret = true; - break; - } + int next_start_pos = text_editor->has_selection(c_next) ? text_editor->get_selection_from_line(c_next) : text_editor->get_caret_line(c_next); + int next_end_pos = text_editor->has_selection(c_next) ? text_editor->get_selection_to_line(c_next) : text_editor->get_caret_line(c_next); + + int current_start_pos = text_editor->has_selection(c_current) ? text_editor->get_selection_from_line(c_current) : text_editor->get_caret_line(c_current); + + i = j; + if (next_end_pos != current_start_pos && next_end_pos + 1 != current_start_pos) { break; } - - if (text_editor->get_caret_line(caret_edit_order[j]) == cl) { - carets_to_remove.push_back(caret_edit_order[j]); - i = j; - continue; + group_border.first = next_start_pos; + new_group.push_back(c_next); + // If the last caret is added to the current group there is no need to process it again + if (j + 1 == caret_edit_order.size() - 1) { + i++; } - break; } + group_borders.push_back(group_border); + caret_groups.push_back(new_group); + } - if (swaped_caret) { + for (int i = group_borders.size() - 1; i >= 0; i--) { + if (group_borders[i].first - 1 < 0) { continue; } - if (text_editor->has_selection(c)) { + // If the group starts overlapping with the upper group don't move it + if (i < group_borders.size() - 1 && group_borders[i].first - 1 <= group_borders[i + 1].second) { + continue; + } + + // We have to remember caret positions and selections prior to line swapping + Vector<Vector<int>> caret_group_parameters; + + for (int j = 0; j < caret_groups[i].size(); j++) { + int c = caret_groups[i][j]; + int cursor_line = text_editor->get_caret_line(c); + int cursor_column = text_editor->get_caret_column(c); + + if (!text_editor->has_selection(c)) { + caret_group_parameters.push_back(Vector<int>{ -1, -1, -1, -1, cursor_line, cursor_column }); + continue; + } int from_line = text_editor->get_selection_from_line(c); int from_col = text_editor->get_selection_from_column(c); int to_line = text_editor->get_selection_to_line(c); int to_column = text_editor->get_selection_to_column(c); - int cursor_line = text_editor->get_caret_line(c); - - for (int j = from_line; j <= to_line; j++) { - int line_id = j; - int next_id = j - 1; + caret_group_parameters.push_back(Vector<int>{ from_line, from_col, to_line, to_column, cursor_line, cursor_column }); + } - if (line_id == 0 || next_id < 0) { - return; - } + for (int line_id = group_borders[i].first; line_id <= group_borders[i].second; line_id++) { + text_editor->unfold_line(line_id); + text_editor->unfold_line(line_id - 1); - text_editor->unfold_line(line_id); - text_editor->unfold_line(next_id); + text_editor->swap_lines(line_id - 1, line_id); + } - text_editor->swap_lines(line_id, next_id); - text_editor->set_caret_line(next_id, c == 0, true, 0, c); - } - int from_line_up = from_line > 0 ? from_line - 1 : from_line; - int to_line_up = to_line > 0 ? to_line - 1 : to_line; - int cursor_line_up = cursor_line > 0 ? cursor_line - 1 : cursor_line; - text_editor->select(from_line_up, from_col, to_line_up, to_column, c); - text_editor->set_caret_line(cursor_line_up, c == 0, true, 0, c); - } else { - int line_id = text_editor->get_caret_line(c); - int next_id = line_id - 1; + for (int j = 0; j < caret_groups[i].size(); j++) { + int c = caret_groups[i][j]; + Vector<int> caret_parameters = caret_group_parameters[j]; + text_editor->set_caret_line(caret_parameters[4] - 1, c == 0, true, 0, c); + text_editor->set_caret_column(caret_parameters[5], c == 0, c); - if (line_id == 0 || next_id < 0) { - return; + if (caret_parameters[0] >= 0) { + text_editor->select(caret_parameters[0] - 1, caret_parameters[1], caret_parameters[2] - 1, caret_parameters[3], c); } - - text_editor->unfold_line(line_id); - text_editor->unfold_line(next_id); - - text_editor->swap_lines(line_id, next_id); - text_editor->set_caret_line(next_id, c == 0, true, 0, c); } } + text_editor->end_complex_operation(); text_editor->merge_overlapping_carets(); text_editor->queue_redraw(); @@ -1382,95 +1396,97 @@ void CodeTextEditor::move_lines_up() { void CodeTextEditor::move_lines_down() { text_editor->begin_complex_operation(); - Vector<int> carets_to_remove; - Vector<int> caret_edit_order = text_editor->get_caret_index_edit_order(); + + // Lists of carets representing each group + Vector<Vector<int>> caret_groups; + Vector<Pair<int, int>> group_borders; + + // Search for groups of carets and their selections residing on the same lines for (int i = 0; i < caret_edit_order.size(); i++) { int c = caret_edit_order[i]; - int cl = text_editor->get_caret_line(c); - bool swaped_caret = false; - for (int j = i + 1; j < caret_edit_order.size(); j++) { - if (text_editor->has_selection(caret_edit_order[j])) { - if (text_editor->get_selection_from_line() == cl) { - carets_to_remove.push_back(caret_edit_order[j]); - continue; - } + Vector<int> new_group{ c }; + Pair<int, int> group_border; + if (text_editor->has_selection(c)) { + group_border.first = text_editor->get_selection_from_line(c); + group_border.second = text_editor->get_selection_to_line(c); + } else { + group_border.first = text_editor->get_caret_line(c); + group_border.second = text_editor->get_caret_line(c); + } - if (text_editor->get_selection_to_line() == cl) { - if (text_editor->has_selection(c)) { - if (text_editor->get_selection_to_line(c) != cl) { - text_editor->select(cl + 1, 0, text_editor->get_selection_to_line(c), text_editor->get_selection_to_column(c), c); - break; - } - } + for (int j = i; j < caret_edit_order.size() - 1; j++) { + int c_current = caret_edit_order[j]; + int c_next = caret_edit_order[j + 1]; - carets_to_remove.push_back(c); - i = j - 1; - swaped_caret = true; - break; + int next_start_pos = text_editor->has_selection(c_next) ? text_editor->get_selection_from_line(c_next) : text_editor->get_caret_line(c_next); + int next_end_pos = text_editor->has_selection(c_next) ? text_editor->get_selection_to_line(c_next) : text_editor->get_caret_line(c_next); + + int current_start_pos = text_editor->has_selection(c_current) ? text_editor->get_selection_from_line(c_current) : text_editor->get_caret_line(c_current); + + i = j; + if (next_end_pos == current_start_pos || next_end_pos + 1 == current_start_pos) { + group_border.first = next_start_pos; + new_group.push_back(c_next); + // If the last caret is added to the current group there is no need to process it again + if (j + 1 == caret_edit_order.size() - 1) { + i++; } + } else { break; } - - if (text_editor->get_caret_line(caret_edit_order[j]) == cl) { - carets_to_remove.push_back(caret_edit_order[j]); - i = j; - continue; - } - break; } + group_borders.push_back(group_border); + caret_groups.push_back(new_group); + } - if (swaped_caret) { + for (int i = 0; i < group_borders.size(); i++) { + if (group_borders[i].second + 1 > text_editor->get_line_count() - 1) { continue; } - if (text_editor->has_selection(c)) { - int from_line = text_editor->get_selection_from_line(c); - int from_col = text_editor->get_selection_from_column(c); - int to_line = text_editor->get_selection_to_line(c); - int to_column = text_editor->get_selection_to_column(c); - int cursor_line = text_editor->get_caret_line(c); - - for (int l = to_line; l >= from_line; l--) { - int line_id = l; - int next_id = l + 1; - - if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) { - continue; - } - - text_editor->unfold_line(line_id); - text_editor->unfold_line(next_id); + // If the group starts overlapping with the upper group don't move it + if (i > 0 && group_borders[i].second + 1 >= group_borders[i - 1].first) { + continue; + } - text_editor->swap_lines(line_id, next_id); - text_editor->set_caret_line(next_id, c == 0, true, 0, c); - } - int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line; - int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line; - int cursor_line_down = cursor_line < text_editor->get_line_count() ? cursor_line + 1 : cursor_line; - text_editor->select(from_line_down, from_col, to_line_down, to_column, c); - text_editor->set_caret_line(cursor_line_down, c == 0, true, 0, c); - } else { - int line_id = text_editor->get_caret_line(c); - int next_id = line_id + 1; + // We have to remember caret positions and selections prior to line swapping + Vector<Vector<int>> caret_group_parameters; - if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) { - continue; + for (int j = 0; j < caret_groups[i].size(); j++) { + int c = caret_groups[i][j]; + int cursor_line = text_editor->get_caret_line(c); + int cursor_column = text_editor->get_caret_column(c); + + if (text_editor->has_selection(c)) { + int from_line = text_editor->get_selection_from_line(c); + int from_col = text_editor->get_selection_from_column(c); + int to_line = text_editor->get_selection_to_line(c); + int to_column = text_editor->get_selection_to_column(c); + caret_group_parameters.push_back(Vector<int>{ from_line, from_col, to_line, to_column, cursor_line, cursor_column }); + } else { + caret_group_parameters.push_back(Vector<int>{ -1, -1, -1, -1, cursor_line, cursor_column }); } + } + for (int line_id = group_borders[i].second; line_id >= group_borders[i].first; line_id--) { text_editor->unfold_line(line_id); - text_editor->unfold_line(next_id); + text_editor->unfold_line(line_id + 1); - text_editor->swap_lines(line_id, next_id); - text_editor->set_caret_line(next_id, c == 0, true, 0, c); + text_editor->swap_lines(line_id + 1, line_id); } - } - // Sort and remove backwards to preserve indexes. - carets_to_remove.sort(); - for (int i = carets_to_remove.size() - 1; i >= 0; i--) { - text_editor->remove_caret(carets_to_remove[i]); + for (int j = 0; j < caret_groups[i].size(); j++) { + int c = caret_groups[i][j]; + Vector<int> caret_parameters = caret_group_parameters[j]; + text_editor->set_caret_line(caret_parameters[4] + 1, c == 0, true, 0, c); + text_editor->set_caret_column(caret_parameters[5], c == 0, c); + + if (caret_parameters[0] >= 0) { + text_editor->select(caret_parameters[0] + 1, caret_parameters[1], caret_parameters[2] + 1, caret_parameters[3], c); + } + } } text_editor->merge_overlapping_carets(); @@ -2002,23 +2018,14 @@ void CodeTextEditor::goto_next_bookmark() { return; } - text_editor->remove_secondary_carets(); - int line = text_editor->get_caret_line(); - if (line >= (int)bmarks[bmarks.size() - 1]) { - text_editor->unfold_line(bmarks[0]); - text_editor->set_caret_line(bmarks[0]); - text_editor->center_viewport_to_caret(); - } else { - for (int i = 0; i < bmarks.size(); i++) { - int bmark_line = bmarks[i]; - if (bmark_line > line) { - text_editor->unfold_line(bmark_line); - text_editor->set_caret_line(bmark_line); - text_editor->center_viewport_to_caret(); - return; - } + int current_line = text_editor->get_caret_line(); + int bmark_idx = 0; + if (current_line < (int)bmarks[bmarks.size() - 1]) { + while (bmark_idx < bmarks.size() && bmarks[bmark_idx] <= current_line) { + bmark_idx++; } } + goto_line_centered(bmarks[bmark_idx]); } void CodeTextEditor::goto_prev_bookmark() { @@ -2027,23 +2034,14 @@ void CodeTextEditor::goto_prev_bookmark() { return; } - text_editor->remove_secondary_carets(); - int line = text_editor->get_caret_line(); - if (line <= (int)bmarks[0]) { - text_editor->unfold_line(bmarks[bmarks.size() - 1]); - text_editor->set_caret_line(bmarks[bmarks.size() - 1]); - text_editor->center_viewport_to_caret(); - } else { - for (int i = bmarks.size() - 1; i >= 0; i--) { - int bmark_line = bmarks[i]; - if (bmark_line < line) { - text_editor->unfold_line(bmark_line); - text_editor->set_caret_line(bmark_line); - text_editor->center_viewport_to_caret(); - return; - } + int current_line = text_editor->get_caret_line(); + int bmark_idx = bmarks.size() - 1; + if (current_line > (int)bmarks[0]) { + while (bmark_idx >= 0 && bmarks[bmark_idx] >= current_line) { + bmark_idx--; } } + goto_line_centered(bmarks[bmark_idx]); } void CodeTextEditor::remove_all_bookmarks() { diff --git a/editor/code_editor.h b/editor/code_editor.h index ded7518287..4d7034fbd0 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -158,6 +158,7 @@ class CodeTextEditor : public VBoxContainer { Label *info = nullptr; Timer *idle = nullptr; Timer *code_complete_timer = nullptr; + int code_complete_timer_line = 0; Timer *font_resize_timer = nullptr; int font_resize_val; diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index ed2044c117..1f0cc1dc77 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -31,6 +31,7 @@ #include "connections_dialog.h" #include "editor/doc_tools.h" +#include "editor/editor_help.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -787,23 +788,7 @@ bool ConnectionsDock::_is_item_signal(TreeItem &p_item) { } bool ConnectionsDock::_is_connection_inherited(Connection &p_connection) { - Node *scene_root = EditorNode::get_singleton()->get_edited_scene(); - Ref<PackedScene> scn = ResourceLoader::load(scene_root->get_scene_file_path()); - ERR_FAIL_NULL_V(scn, false); - - Ref<SceneState> state = scn->get_state(); - ERR_FAIL_NULL_V(state, false); - - Node *source = Object::cast_to<Node>(p_connection.signal.get_object()); - Node *target = Object::cast_to<Node>(p_connection.callable.get_object()); - - const NodePath source_path = scene_root->get_path_to(source); - const NodePath target_path = scene_root->get_path_to(target); - const StringName signal_name = p_connection.signal.get_name(); - const StringName method_name = p_connection.callable.get_method(); - - // If it cannot be found in PackedScene, this connection was inherited. - return !state->has_connection(source_path, signal_name, target_path, method_name, true); + return bool(p_connection.flags & CONNECT_INHERITED); } /* diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp index 785476d75b..5292b51032 100644 --- a/editor/create_dialog.cpp +++ b/editor/create_dialog.cpp @@ -275,7 +275,8 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String r_item->set_text(0, "\"" + p_type + "\""); } else if (script_type) { r_item->set_metadata(0, p_type); - r_item->set_text(0, p_type + " (" + ScriptServer::get_global_class_path(p_type).get_file() + ")"); + r_item->set_text(0, p_type); + r_item->set_suffix(0, "(" + ScriptServer::get_global_class_path(p_type).get_file() + ")"); } else { r_item->set_metadata(0, custom_type_parents[p_type]); r_item->set_text(0, p_type); @@ -283,8 +284,9 @@ void CreateDialog::_configure_search_option_item(TreeItem *r_item, const String bool can_instantiate = (p_type_category == TypeCategory::CPP_TYPE && ClassDB::can_instantiate(p_type)) || p_type_category == TypeCategory::OTHER_TYPE; + bool is_virtual = ClassDB::class_exists(p_type) && ClassDB::is_virtual(p_type); - if (can_instantiate && !ClassDB::is_virtual(p_type)) { + if (can_instantiate && !is_virtual) { r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, icon_fallback)); } else { r_item->set_icon(0, EditorNode::get_singleton()->get_class_icon(p_type, "NodeDisabled")); diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp index 150257a95c..610f467faa 100644 --- a/editor/debugger/editor_debugger_node.cpp +++ b/editor/debugger/editor_debugger_node.cpp @@ -35,6 +35,8 @@ #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_log.h" #include "editor/editor_node.h" +#include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" @@ -207,9 +209,32 @@ String EditorDebuggerNode::get_server_uri() const { return server->get_uri(); } +void EditorDebuggerNode::set_keep_open(bool p_keep_open) { + keep_open = p_keep_open; + if (keep_open) { + if (server.is_null() || !server->is_active()) { + start(); + } + } else { + bool found = false; + _for_all(tabs, [&](ScriptEditorDebugger *p_debugger) { + if (p_debugger->is_session_active()) { + found = true; + } + }); + if (!found) { + stop(); + } + } +} + Error EditorDebuggerNode::start(const String &p_uri) { - stop(); ERR_FAIL_COND_V(p_uri.find("://") < 0, ERR_INVALID_PARAMETER); + if (keep_open && current_uri == p_uri && server.is_valid()) { + return OK; + } + stop(true); + current_uri = p_uri; if (EDITOR_GET("run/output/always_open_output_on_play")) { EditorNode::get_singleton()->make_bottom_panel_item_visible(EditorNode::get_log()); } else { @@ -225,7 +250,11 @@ Error EditorDebuggerNode::start(const String &p_uri) { return OK; } -void EditorDebuggerNode::stop() { +void EditorDebuggerNode::stop(bool p_force) { + if (keep_open && !p_force) { + return; + } + current_uri.clear(); if (server.is_valid()) { server->stop(); EditorNode::get_log()->add_message("--- Debugging process stopped ---", EditorLog::MSG_TYPE_EDITOR); @@ -244,11 +273,6 @@ void EditorDebuggerNode::stop() { } }); _break_state_changed(); - if (hide_on_stop) { - if (is_visible_in_tree()) { - EditorNode::get_singleton()->hide_bottom_panel(); - } - } breakpoints.clear(); set_process(false); } @@ -428,7 +452,6 @@ void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) { p->add_shortcut(ED_GET_SHORTCUT("debugger/break"), DEBUG_BREAK); p->add_shortcut(ED_GET_SHORTCUT("debugger/continue"), DEBUG_CONTINUE); p->add_separator(); - p->add_check_shortcut(ED_GET_SHORTCUT("debugger/keep_debugger_open"), DEBUG_KEEP_DEBUGGER_OPEN); p->add_check_shortcut(ED_GET_SHORTCUT("debugger/debug_with_external_editor"), DEBUG_WITH_EXTERNAL_EDITOR); p->connect("id_pressed", callable_mp(this, &EditorDebuggerNode::_menu_option)); @@ -468,12 +491,6 @@ void EditorDebuggerNode::_menu_option(int p_id) { case DEBUG_CONTINUE: { debug_continue(); } break; - case DEBUG_KEEP_DEBUGGER_OPEN: { - bool ischecked = script_menu->get_popup()->is_item_checked(script_menu->get_popup()->get_item_index(DEBUG_KEEP_DEBUGGER_OPEN)); - hide_on_stop = ischecked; - script_menu->get_popup()->set_item_checked(script_menu->get_popup()->get_item_index(DEBUG_KEEP_DEBUGGER_OPEN), !ischecked); - EditorSettings::get_singleton()->set_project_metadata("debug_options", "keep_debugger_open", !ischecked); - } break; case DEBUG_WITH_EXTERNAL_EDITOR: { bool ischecked = script_menu->get_popup()->is_item_checked(script_menu->get_popup()->get_item_index(DEBUG_WITH_EXTERNAL_EDITOR)); debug_with_external_editor = !ischecked; @@ -484,9 +501,6 @@ void EditorDebuggerNode::_menu_option(int p_id) { } void EditorDebuggerNode::_update_debug_options() { - if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "keep_debugger_open", false).operator bool()) { - _menu_option(DEBUG_KEEP_DEBUGGER_OPEN); - } if (EditorSettings::get_singleton()->get_project_metadata("debug_options", "debug_with_external_editor", false).operator bool()) { _menu_option(DEBUG_WITH_EXTERNAL_EDITOR); } diff --git a/editor/debugger/editor_debugger_node.h b/editor/debugger/editor_debugger_node.h index 7f7279ae74..030f4c7d12 100644 --- a/editor/debugger/editor_debugger_node.h +++ b/editor/debugger/editor_debugger_node.h @@ -63,7 +63,6 @@ private: DEBUG_STEP, DEBUG_BREAK, DEBUG_CONTINUE, - DEBUG_KEEP_DEBUGGER_OPEN, DEBUG_WITH_EXTERNAL_EDITOR, }; @@ -110,7 +109,9 @@ private: float remote_scene_tree_timeout = 0.0; bool auto_switch_remote_scene_tree = false; bool debug_with_external_editor = false; - bool hide_on_stop = true; + bool keep_open = false; + String current_uri; + CameraOverride camera_override = OVERRIDE_NONE; HashMap<Breakpoint, bool, Breakpoint> breakpoints; @@ -203,8 +204,9 @@ public: String get_server_uri() const; + void set_keep_open(bool p_keep_open); Error start(const String &p_uri = "tcp://"); - void stop(); + void stop(bool p_force = false); bool plugins_capture(ScriptEditorDebugger *p_debugger, const String &p_message, const Array &p_data); void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin); diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp index 4168efda26..8b31781c5e 100644 --- a/editor/debugger/editor_debugger_tree.cpp +++ b/editor/debugger/editor_debugger_tree.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/scene_tree_dock.h" #include "scene/debugger/scene_debugger.h" +#include "scene/gui/texture_rect.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" diff --git a/editor/debugger/script_editor_debugger.cpp b/editor/debugger/script_editor_debugger.cpp index 178010d852..deca638f3b 100644 --- a/editor/debugger/script_editor_debugger.cpp +++ b/editor/debugger/script_editor_debugger.cpp @@ -46,6 +46,7 @@ #include "editor/editor_property_name_processor.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" @@ -53,6 +54,7 @@ #include "scene/3d/camera_3d.h" #include "scene/debugger/scene_debugger.h" #include "scene/gui/dialogs.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" @@ -1656,6 +1658,8 @@ ScriptEditorDebugger::ScriptEditorDebugger() { add_child(tabs); + InspectorDock::get_inspector_singleton()->connect("object_id_selected", callable_mp(this, &ScriptEditorDebugger::_remote_object_selected)); + { //debugger VBoxContainer *vbc = memnew(VBoxContainer); vbc->set_name(TTR("Debugger")); diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp index 14a2640e63..65e73d8df4 100644 --- a/editor/doc_tools.cpp +++ b/editor/doc_tools.cpp @@ -701,7 +701,7 @@ void DocTools::generate(bool p_basic_types) { if (rt != Variant::NIL) { // Has operator. // Skip String % operator as it's registered separately for each Variant arg type, // we'll add it manually below. - if (i == Variant::STRING && Variant::Operator(j) == Variant::OP_MODULE) { + if ((i == Variant::STRING || i == Variant::STRING_NAME) && Variant::Operator(j) == Variant::OP_MODULE) { continue; } MethodInfo mi; @@ -718,7 +718,7 @@ void DocTools::generate(bool p_basic_types) { } } - if (i == Variant::STRING) { + if (i == Variant::STRING || i == Variant::STRING_NAME) { // We skipped % operator above, and we register it manually once for Variant arg type here. MethodInfo mi; mi.name = "operator %"; diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp index 24116a8053..a040d918df 100644 --- a/editor/editor_audio_buses.cpp +++ b/editor/editor_audio_buses.cpp @@ -40,6 +40,7 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "filesystem_dock.h" +#include "scene/gui/separator.h" #include "scene/resources/font.h" #include "servers/audio_server.h" diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 598bcdc639..41b3d45a1f 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -400,27 +400,38 @@ void EditorAutoloadSettings::_autoload_text_changed(const String p_name) { } Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { - Ref<Resource> res = ResourceLoader::load(p_path); - ERR_FAIL_COND_V_MSG(res.is_null(), nullptr, "Can't autoload: " + p_path + "."); Node *n = nullptr; - Ref<PackedScene> scn = res; - Ref<Script> scr = res; - if (scn.is_valid()) { - n = scn->instantiate(); - } else if (scr.is_valid()) { - StringName ibt = scr->get_instance_base_type(); - bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_FAIL_COND_V_MSG(!valid_type, nullptr, "Script does not inherit from Node: " + p_path + "."); + if (ResourceLoader::get_resource_type(p_path) == "PackedScene") { + // Cache the scene reference before loading it (for cyclic references) + Ref<PackedScene> scn; + scn.instantiate(); + scn->set_path(p_path); + scn->reload_from_file(); + ERR_FAIL_COND_V_MSG(!scn.is_valid(), nullptr, vformat("Can't autoload: %s.", p_path)); - Object *obj = ClassDB::instantiate(ibt); + if (scn.is_valid()) { + n = scn->instantiate(); + } + } else { + Ref<Resource> res = ResourceLoader::load(p_path); + ERR_FAIL_COND_V_MSG(res.is_null(), nullptr, vformat("Can't autoload: %s.", p_path)); + + Ref<Script> scr = res; + if (scr.is_valid()) { + StringName ibt = scr->get_instance_base_type(); + bool valid_type = ClassDB::is_parent_class(ibt, "Node"); + ERR_FAIL_COND_V_MSG(!valid_type, nullptr, vformat("Script does not inherit from Node: %s.", p_path)); + + Object *obj = ClassDB::instantiate(ibt); - ERR_FAIL_COND_V_MSG(!obj, nullptr, "Cannot instance script for Autoload, expected 'Node' inheritance, got: " + String(ibt) + "."); + ERR_FAIL_COND_V_MSG(!obj, nullptr, vformat("Cannot instance script for Autoload, expected 'Node' inheritance, got: %s.", ibt)); - n = Object::cast_to<Node>(obj); - n->set_script(scr); + n = Object::cast_to<Node>(obj); + n->set_script(scr); + } } - ERR_FAIL_COND_V_MSG(!n, nullptr, "Path in Autoload not a node or script: " + p_path + "."); + ERR_FAIL_COND_V_MSG(!n, nullptr, vformat("Path in Autoload not a node or script: %s.", p_path)); return n; } @@ -530,8 +541,6 @@ void EditorAutoloadSettings::update_autoload() { info.node->queue_free(); info.node = nullptr; } - - ProjectSettings::get_singleton()->remove_autoload(info.name); } // Load new/changed autoloads @@ -556,12 +565,6 @@ void EditorAutoloadSettings::update_autoload() { } } - ProjectSettings::AutoloadInfo prop_info; - prop_info.name = info->name; - prop_info.path = info->path; - prop_info.is_singleton = info->is_singleton; - ProjectSettings::get_singleton()->add_autoload(prop_info); - if (!info->in_editor && !info->is_singleton) { // No reason to keep this node memdelete(info->node); diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp index b92b0fca59..609afeb40a 100644 --- a/editor/editor_command_palette.cpp +++ b/editor/editor_command_palette.cpp @@ -38,6 +38,9 @@ EditorCommandPalette *EditorCommandPalette::singleton = nullptr; +static Rect2i prev_rect = Rect2i(); +static bool was_showed = false; + float EditorCommandPalette::_score_path(const String &p_search, const String &p_path) { float score = 0.9f + .1f * (p_search.length() / (float)p_path.length()); @@ -145,6 +148,17 @@ void EditorCommandPalette::_bind_methods() { ClassDB::bind_method(D_METHOD("remove_command", "key_name"), &EditorCommandPalette::remove_command); } +void EditorCommandPalette::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + prev_rect = Rect2i(get_position(), get_size()); + was_showed = true; + } + } break; + } +} + void EditorCommandPalette::_sbox_input(const Ref<InputEvent> &p_ie) { Ref<InputEventKey> k = p_ie; if (k.is_valid()) { @@ -171,12 +185,10 @@ void EditorCommandPalette::_confirmed() { } void EditorCommandPalette::open_popup() { - static bool was_showed = false; - if (!was_showed) { - was_showed = true; - popup_centered_clamped(Size2(600, 440) * EDSCALE, 0.8f); + if (was_showed) { + popup(prev_rect); } else { - show(); + popup_centered_clamped(Size2(600, 440) * EDSCALE, 0.8f); } command_search_box->clear(); diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h index 15200552b4..81cf401851 100644 --- a/editor/editor_command_palette.h +++ b/editor/editor_command_palette.h @@ -91,6 +91,7 @@ class EditorCommandPalette : public ConfirmationDialog { protected: static void _bind_methods(); + void _notification(int p_what); public: void open_popup(); diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index 48be0c9c00..f15b874c45 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -945,11 +945,11 @@ StringName EditorData::script_class_get_base(const String &p_class) const { Variant EditorData::script_class_instance(const String &p_class) { if (ScriptServer::is_global_class(p_class)) { - Variant obj = ClassDB::instantiate(ScriptServer::get_global_class_native_base(p_class)); - if (obj) { - Ref<Script> script = script_class_load_script(p_class); - if (script.is_valid()) { - ((Object *)obj)->set_script(script); + Ref<Script> script = script_class_load_script(p_class); + if (script.is_valid()) { + Object *obj = ClassDB::instantiate(script->get_instance_base_type()); + if (obj) { + obj->set_script(script); } return obj; } diff --git a/editor/editor_feature_profile.cpp b/editor/editor_feature_profile.cpp index 49fb16a095..7080cdbdd5 100644 --- a/editor/editor_feature_profile.cpp +++ b/editor/editor_feature_profile.cpp @@ -309,7 +309,11 @@ void EditorFeatureProfile::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_MAX); } -EditorFeatureProfile::EditorFeatureProfile() {} +EditorFeatureProfile::EditorFeatureProfile() { + for (int i = 0; i < FEATURE_MAX; i++) { + features_disabled[i] = false; + } +} ////////////////////////// @@ -746,6 +750,8 @@ void EditorFeatureProfileManager::_update_selected_profile() { class_list->clear(); String profile = _get_selected_profile(); + profile_actions[PROFILE_SET]->set_disabled(profile == current_profile); + if (profile.is_empty()) { //nothing selected, nothing edited property_list->clear(); edited.unref(); diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index ee02916a5f..55c512f77d 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -34,7 +34,6 @@ #include "core/io/file_access.h" #include "core/os/keyboard.h" #include "core/os/os.h" -#include "core/string/print_string.h" #include "dependency_editor.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" @@ -44,6 +43,10 @@ #include "scene/gui/center_container.h" #include "scene/gui/label.h" #include "scene/gui/margin_container.h" +#include "scene/gui/option_button.h" +#include "scene/gui/separator.h" +#include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "servers/display_server.h" EditorFileDialog::GetIconFunc EditorFileDialog::get_icon_func = nullptr; diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 2e7302aaf9..40073326a1 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -32,17 +32,14 @@ #define EDITOR_FILE_DIALOG_H #include "core/io/dir_access.h" -#include "editor/plugins/editor_preview_plugins.h" -#include "scene/gui/box_container.h" #include "scene/gui/dialogs.h" -#include "scene/gui/item_list.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/option_button.h" -#include "scene/gui/separator.h" -#include "scene/gui/split_container.h" -#include "scene/gui/texture_rect.h" class DependencyRemoveDialog; +class HSplitContainer; +class ItemList; +class OptionButton; +class PopupMenu; +class TextureRect; class EditorFileDialog : public ConfirmationDialog { GDCLASS(EditorFileDialog, ConfirmationDialog); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index ce06631fdd..b98480b594 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -31,7 +31,7 @@ #include "editor_file_system.h" #include "core/config/project_settings.h" -#include "core/extension/native_extension_manager.h" +#include "core/extension/gdextension_manager.h" #include "core/io/file_access.h" #include "core/io/resource_importer.h" #include "core/io/resource_loader.h" @@ -39,6 +39,7 @@ #include "core/object/worker_thread_pool.h" #include "core/os/os.h" #include "core/variant/variant_parser.h" +#include "editor/editor_help.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_resource_preview.h" @@ -619,7 +620,12 @@ bool EditorFileSystem::_update_scan_actions() { if (_test_for_reimport(full_path, false)) { //must reimport reimports.push_back(full_path); - reimports.append_array(_get_dependencies(full_path)); + Vector<String> dependencies = _get_dependencies(full_path); + for (const String &dependency_path : dependencies) { + if (import_extensions.has(dependency_path.get_extension())) { + reimports.push_back(dependency_path); + } + } } else { //must not reimport, all was good //update modified times, to avoid reimport @@ -1636,6 +1642,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector String importer_name; HashMap<String, HashMap<StringName, Variant>> source_file_options; + HashMap<String, ResourceUID::ID> uids; HashMap<String, String> base_paths; for (int i = 0; i < p_files.size(); i++) { Ref<ConfigFile> config; @@ -1651,6 +1658,15 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector ERR_FAIL_V(ERR_FILE_CORRUPT); } + ResourceUID::ID uid = ResourceUID::INVALID_ID; + + if (config->has_section_key("remap", "uid")) { + String uidt = config->get_value("remap", "uid"); + uid = ResourceUID::get_singleton()->text_to_id(uidt); + } + + uids[p_files[i]] = uid; + source_file_options[p_files[i]] = HashMap<StringName, Variant>(); importer_name = file_importer_name; @@ -1695,6 +1711,7 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector const String &file = E.key; String base_path = ResourceFormatImporter::get_singleton()->get_import_base_path(file); Vector<String> dest_paths; + ResourceUID::ID uid = uids[file]; { Ref<FileAccess> f = FileAccess::open(file + ".import", FileAccess::WRITE); ERR_FAIL_COND_V_MSG(f.is_null(), ERR_FILE_CANT_OPEN, "Cannot open import file '" + file + ".import'."); @@ -1711,6 +1728,12 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector f->store_line("type=\"" + importer->get_resource_type() + "\""); } + if (uid == ResourceUID::INVALID_ID) { + uid = ResourceUID::get_singleton()->create_id(); + } + + f->store_line("uid=\"" + ResourceUID::get_singleton()->id_to_text(uid) + "\""); // Store in readable format. + if (err == OK) { String path = base_path + "." + importer->get_save_extension(); f->store_line("path=\"" + path + "\""); @@ -1776,12 +1799,19 @@ Error EditorFileSystem::_reimport_group(const String &p_group_file, const Vector fs->files[cpos]->modified_time = FileAccess::get_modified_time(file); fs->files[cpos]->import_modified_time = FileAccess::get_modified_time(file + ".import"); fs->files[cpos]->deps = _get_dependencies(file); + fs->files[cpos]->uid = uid; fs->files[cpos]->type = importer->get_resource_type(); if (fs->files[cpos]->type == "" && textfile_extensions.has(file.get_extension())) { fs->files[cpos]->type = "TextFile"; } fs->files[cpos]->import_valid = err == OK; + if (ResourceUID::get_singleton()->has_id(uid)) { + ResourceUID::get_singleton()->set_id(uid, file); + } else { + ResourceUID::get_singleton()->add_id(uid, file); + } + //if file is currently up, maybe the source it was loaded from changed, so import math must be updated for it //to reload properly Ref<Resource> r = ResourceCache::get_ref(file); @@ -2068,6 +2098,8 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { importing = true; EditorProgress pr("reimport", TTR("(Re)Importing Assets"), p_files.size()); + Vector<String> reloads; + Vector<ImportFile> reimport_files; HashSet<String> groups_to_reimport; @@ -2083,22 +2115,26 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { String group_file = ResourceFormatImporter::get_singleton()->get_import_group_file(file); if (group_file_cache.has(file)) { - //maybe the file itself is a group! + // Maybe the file itself is a group! groups_to_reimport.insert(file); - //groups do not belong to groups + // Groups do not belong to groups. + group_file = String(); + } else if (groups_to_reimport.has(file)) { + // Groups do not belong to groups. group_file = String(); } else if (!group_file.is_empty()) { - //it's a group file, add group to import and skip this file + // It's a group file, add group to import and skip this file. groups_to_reimport.insert(group_file); } else { - //it's a regular file + // It's a regular file. ImportFile ifile; ifile.path = file; ResourceFormatImporter::get_singleton()->get_import_order_threads_and_importer(file, ifile.order, ifile.threaded, ifile.importer); + reloads.push_back(file); reimport_files.push_back(ifile); } - //group may have changed, so also update group reference + // Group may have changed, so also update group reference. EditorFileSystemDirectory *fs = nullptr; int cpos = -1; if (_find_file(file, &fs, cpos)) { @@ -2112,10 +2148,14 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { int from = 0; for (int i = 0; i < reimport_files.size(); i++) { + if (groups_to_reimport.has(reimport_files[i].path)) { + continue; + } + if (use_multiple_threads && reimport_files[i].threaded) { if (i + 1 == reimport_files.size() || reimport_files[i + 1].importer != reimport_files[from].importer) { if (from - i == 0) { - //single file, do not use threads + // Single file, do not use threads. pr.step(reimport_files[i].path.get_file(), i); _reimport_file(reimport_files[i].path); } else { @@ -2153,20 +2193,25 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { } } - //reimport groups + // Reimport groups. + + from = reimport_files.size(); if (groups_to_reimport.size()) { HashMap<String, Vector<String>> group_files; _find_group_files(filesystem, group_files, groups_to_reimport); for (const KeyValue<String, Vector<String>> &E : group_files) { + pr.step(E.key.get_file(), from++); Error err = _reimport_group(E.key, E.value); + reloads.push_back(E.key); + reloads.append_array(E.value); if (err == OK) { _reimport_file(E.key); } } } - ResourceUID::get_singleton()->update_cache(); //after reimporting, update the cache + ResourceUID::get_singleton()->update_cache(); // After reimporting, update the cache. _save_filesystem_cache(); importing = false; @@ -2174,7 +2219,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { emit_signal(SNAME("filesystem_changed")); } - emit_signal(SNAME("resources_reimported"), p_files); + emit_signal(SNAME("resources_reimported"), reloads); } Error EditorFileSystem::_resource_import(const String &p_path) { @@ -2290,7 +2335,7 @@ ResourceUID::ID EditorFileSystem::_resource_saver_get_resource_id_for_path(const static void _scan_extensions_dir(EditorFileSystemDirectory *d, HashSet<String> &extensions) { int fc = d->get_file_count(); for (int i = 0; i < fc; i++) { - if (d->get_file_type(i) == SNAME("NativeExtension")) { + if (d->get_file_type(i) == SNAME("GDExtension")) { extensions.insert(d->get_file_path(i)); } } @@ -2311,19 +2356,19 @@ bool EditorFileSystem::_scan_extensions() { Vector<String> extensions_removed; for (const String &E : extensions) { - if (!NativeExtensionManager::get_singleton()->is_extension_loaded(E)) { + if (!GDExtensionManager::get_singleton()->is_extension_loaded(E)) { extensions_added.push_back(E); } } - Vector<String> loaded_extensions = NativeExtensionManager::get_singleton()->get_loaded_extensions(); + Vector<String> loaded_extensions = GDExtensionManager::get_singleton()->get_loaded_extensions(); for (int i = 0; i < loaded_extensions.size(); i++) { if (!extensions.has(loaded_extensions[i])) { extensions_removed.push_back(loaded_extensions[i]); } } - String extension_list_config_file = NativeExtension::get_extension_list_config_file(); + String extension_list_config_file = GDExtension::get_extension_list_config_file(); if (extensions.size()) { if (extensions_added.size() || extensions_removed.size()) { //extensions were added or removed Ref<FileAccess> f = FileAccess::open(extension_list_config_file, FileAccess::WRITE); @@ -2340,18 +2385,18 @@ bool EditorFileSystem::_scan_extensions() { bool needs_restart = false; for (int i = 0; i < extensions_added.size(); i++) { - NativeExtensionManager::LoadStatus st = NativeExtensionManager::get_singleton()->load_extension(extensions_added[i]); - if (st == NativeExtensionManager::LOAD_STATUS_FAILED) { + GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->load_extension(extensions_added[i]); + if (st == GDExtensionManager::LOAD_STATUS_FAILED) { EditorNode::get_singleton()->add_io_error("Error loading extension: " + extensions_added[i]); - } else if (st == NativeExtensionManager::LOAD_STATUS_NEEDS_RESTART) { + } else if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) { needs_restart = true; } } for (int i = 0; i < extensions_removed.size(); i++) { - NativeExtensionManager::LoadStatus st = NativeExtensionManager::get_singleton()->unload_extension(extensions_removed[i]); - if (st == NativeExtensionManager::LOAD_STATUS_FAILED) { + GDExtensionManager::LoadStatus st = GDExtensionManager::get_singleton()->unload_extension(extensions_removed[i]); + if (st == GDExtensionManager::LOAD_STATUS_FAILED) { EditorNode::get_singleton()->add_io_error("Error removing extension: " + extensions_added[i]); - } else if (st == NativeExtensionManager::LOAD_STATUS_NEEDS_RESTART) { + } else if (st == GDExtensionManager::LOAD_STATUS_NEEDS_RESTART) { needs_restart = true; } } diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index e7d4636ad9..cf413133aa 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -41,7 +41,7 @@ Ref<FontFile> load_external_font(const String &p_path, TextServer::Hinting p_hin Ref<FontFile> font; font.instantiate(); - Vector<uint8_t> data = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_path); font->set_data(data); font->set_multichannel_signed_distance_field(p_msdf); diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 676e4b0b33..21119048cb 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -39,6 +39,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/plugins/script_editor_plugin.h" +#include "scene/gui/line_edit.h" #define CONTRIBUTE_URL vformat("%s/community/contributing/updating_the_class_reference.html", VERSION_DOCS_URL) @@ -54,8 +55,6 @@ void EditorHelp::_update_theme() { qualifier_color = get_theme_color(SNAME("qualifier_color"), SNAME("EditorHelp")); type_color = get_theme_color(SNAME("type_color"), SNAME("EditorHelp")); - class_desc->add_theme_style_override("normal", get_theme_stylebox(SNAME("background"), SNAME("EditorHelp"))); - class_desc->add_theme_style_override("focus", get_theme_stylebox(SNAME("background"), SNAME("EditorHelp"))); class_desc->add_theme_color_override("selection_color", get_theme_color(SNAME("selection_color"), SNAME("EditorHelp"))); class_desc->add_theme_constant_override("line_separation", get_theme_constant(SNAME("line_separation"), SNAME("EditorHelp"))); class_desc->add_theme_constant_override("table_h_separation", get_theme_constant(SNAME("table_h_separation"), SNAME("EditorHelp"))); @@ -195,10 +194,11 @@ void EditorHelp::_class_desc_resized(bool p_force_update_theme) { if (display_margin != new_display_margin || p_force_update_theme) { display_margin = new_display_margin; - Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox(SNAME("normal"), SNAME("RichTextLabel"))->duplicate(); + Ref<StyleBox> class_desc_stylebox = EditorNode::get_singleton()->get_theme_base()->get_theme_stylebox(SNAME("background"), SNAME("EditorHelp"))->duplicate(); class_desc_stylebox->set_default_margin(SIDE_LEFT, display_margin); class_desc_stylebox->set_default_margin(SIDE_RIGHT, display_margin); class_desc->add_theme_style_override("normal", class_desc_stylebox); + class_desc->add_theme_style_override("focused", class_desc_stylebox); } } diff --git a/editor/editor_help_search.cpp b/editor/editor_help_search.cpp index 286dcf4b8e..b48fbb805a 100644 --- a/editor/editor_help_search.cpp +++ b/editor/editor_help_search.cpp @@ -443,6 +443,10 @@ bool EditorHelpSearch::Runner::_phase_member_items_init() { } bool EditorHelpSearch::Runner::_phase_member_items() { + if (!iterator_match) { + return true; + } + ClassMatch &match = iterator_match->value; if (!match.doc || match.doc->name.is_empty()) { diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 4822aab7d4..a5397a8e6a 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -30,9 +30,7 @@ #include "editor_inspector.h" -#include "array_property_edit.h" #include "core/os/keyboard.h" -#include "dictionary_property_edit.h" #include "editor/doc_tools.h" #include "editor/editor_feature_profile.h" #include "editor/editor_node.h" @@ -40,9 +38,11 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/script_editor_plugin.h" #include "multi_node_edit.h" -#include "scene/gui/center_container.h" +#include "scene/gui/spin_box.h" +#include "scene/gui/texture_rect.h" #include "scene/property_utils.h" #include "scene/resources/packed_scene.h" @@ -660,6 +660,7 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } if (keying_rect.has_point(mpos)) { + accept_event(); emit_signal(SNAME("property_keyed"), property, use_keying_next()); if (use_keying_next()) { @@ -683,10 +684,12 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } } if (delete_rect.has_point(mpos)) { + accept_event(); emit_signal(SNAME("property_deleted"), property); } if (revert_rect.has_point(mpos)) { + accept_event(); bool is_valid_revert = false; Variant revert_value = EditorPropertyRevert::get_property_revert_value(object, property, &is_valid_revert); ERR_FAIL_COND(!is_valid_revert); @@ -695,11 +698,13 @@ void EditorProperty::gui_input(const Ref<InputEvent> &p_event) { } if (check_rect.has_point(mpos)) { + accept_event(); checked = !checked; queue_redraw(); emit_signal(SNAME("property_checked"), property, checked); } } else if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::RIGHT) { + accept_event(); _update_popup(); menu->set_position(get_screen_position() + get_local_mouse_position()); menu->reset_size(); @@ -1482,6 +1487,8 @@ void EditorInspectorSection::gui_input(const Ref<InputEvent> &p_event) { return; } + accept_event(); + bool should_unfold = !object->editor_is_section_unfolded(section); if (should_unfold) { unfold(); @@ -1680,6 +1687,7 @@ void EditorInspectorArray::_panel_gui_input(Ref<InputEvent> p_event, int p_index Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid()) { if (movable && mb->get_button_index() == MouseButton::RIGHT) { + array_elements[p_index].panel->accept_event(); popup_array_index_pressed = begin_array_index + p_index; rmb_popup->set_item_disabled(OPTION_MOVE_UP, popup_array_index_pressed == 0); rmb_popup->set_item_disabled(OPTION_MOVE_DOWN, popup_array_index_pressed == count - 1); diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index 1b93b19845..41651494ce 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -33,14 +33,17 @@ #include "editor_property_name_processor.h" #include "scene/gui/box_container.h" -#include "scene/gui/button.h" -#include "scene/gui/dialogs.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/option_button.h" -#include "scene/gui/panel_container.h" #include "scene/gui/scroll_container.h" -#include "scene/gui/spin_box.h" -#include "scene/gui/texture_rect.h" + +class AcceptDialog; +class Button; +class ConfirmationDialog; +class LineEdit; +class OptionButton; +class PanelContainer; +class PopupMenu; +class SpinBox; +class TextureRect; class EditorPropertyRevert { public: diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 7c297a39d0..463e8f6bdc 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -37,7 +37,6 @@ #include "core/io/image_loader.h" #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" -#include "core/io/stream_peer_tls.h" #include "core/object/class_db.h" #include "core/object/message_queue.h" #include "core/os/keyboard.h" @@ -47,10 +46,7 @@ #include "core/string/translation.h" #include "core/version.h" #include "main/main.h" -#include "scene/3d/importer_mesh_instance_3d.h" -#include "scene/gui/center_container.h" #include "scene/gui/color_picker.h" -#include "scene/gui/control.h" #include "scene/gui/dialogs.h" #include "scene/gui/file_dialog.h" #include "scene/gui/link_button.h" @@ -61,17 +57,13 @@ #include "scene/gui/split_container.h" #include "scene/gui/tab_bar.h" #include "scene/gui/tab_container.h" -#include "scene/gui/texture_progress_bar.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" #include "servers/display_server.h" -#include "servers/navigation_server_2d.h" #include "servers/navigation_server_3d.h" #include "servers/physics_server_2d.h" -#include "servers/rendering/rendering_device.h" #include "editor/audio_stream_preview.h" -#include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/dependency_editor.h" #include "editor/editor_about.h" @@ -90,12 +82,13 @@ #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "editor/editor_property_name_processor.h" +#include "editor/editor_quick_open.h" +#include "editor/editor_resource_preview.h" #include "editor/editor_run.h" #include "editor/editor_run_native.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_settings_dialog.h" -#include "editor/editor_spin_slider.h" #include "editor/editor_themes.h" #include "editor/editor_toaster.h" #include "editor/editor_translation_parser.h" @@ -108,7 +101,6 @@ #include "editor/import/audio_stream_import_settings.h" #include "editor/import/dynamic_font_import_settings.h" #include "editor/import/editor_import_collada.h" -#include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_bitmask.h" #include "editor/import/resource_importer_bmfont.h" #include "editor/import/resource_importer_csv_translation.h" @@ -123,6 +115,7 @@ #include "editor/import/resource_importer_wav.h" #include "editor/import/scene_import_settings.h" #include "editor/import_dock.h" +#include "editor/inspector_dock.h" #include "editor/multi_node_edit.h" #include "editor/node_dock.h" #include "editor/plugin_config_dialog.h" @@ -130,6 +123,7 @@ #include "editor/plugins/asset_library_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/debugger_editor_plugin.h" +#include "editor/plugins/editor_preview_plugins.h" #include "editor/plugins/editor_resource_conversion_plugin.h" #include "editor/plugins/gdextension_export_plugin.h" #include "editor/plugins/material_editor_plugin.h" @@ -1200,6 +1194,10 @@ void EditorNode::edit_node(Node *p_node) { push_item(p_node); } +void EditorNode::edit_resource(const Ref<Resource> &p_resource) { + InspectorDock::get_singleton()->edit_resource(p_resource); +} + void EditorNode::save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path) { editor_data.apply_changes_in_editors(); int flg = 0; @@ -2276,7 +2274,9 @@ void EditorNode::_edit_current(bool p_skip_foreign) { } else { Node *selected_node = nullptr; - if (current_obj->is_class("MultiNodeEdit")) { + if (current_obj->is_class("EditorDebuggerRemoteObject")) { + disable_folding = true; + } else if (current_obj->is_class("MultiNodeEdit")) { Node *scene = get_edited_scene(); if (scene) { MultiNodeEdit *multi_node_edit = Object::cast_to<MultiNodeEdit>(current_obj); @@ -3358,7 +3358,9 @@ void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { if (p_editor->has_main_screen()) { - for (int i = 0; i < singleton->main_editor_buttons.size(); i++) { + // Remove the main editor button and update the bindings of + // all buttons behind it to point to the correct main window. + for (int i = singleton->main_editor_buttons.size() - 1; i >= 0; i--) { if (p_editor->get_name() == singleton->main_editor_buttons[i]->get_text()) { if (singleton->main_editor_buttons[i]->is_pressed()) { singleton->editor_select(EDITOR_SCRIPT); @@ -3368,6 +3370,9 @@ void EditorNode::remove_editor_plugin(EditorPlugin *p_editor, bool p_config_chan singleton->main_editor_buttons.remove_at(i); break; + } else { + singleton->main_editor_buttons[i]->disconnect("pressed", callable_mp(singleton, &EditorNode::editor_select)); + singleton->main_editor_buttons[i]->connect("pressed", callable_mp(singleton, &EditorNode::editor_select).bind(i - 1)); } } @@ -4883,7 +4888,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String Vector<String> names = String(p_layout->get_value(p_section, "dock_" + itos(i + 1))).split(","); - for (int j = 0; j < names.size(); j++) { + for (int j = names.size() - 1; j >= 0; j--) { String name = names[j]; // FIXME: Find it, in a horribly inefficient way. int atidx = -1; @@ -4904,7 +4909,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String } if (atidx == i) { - node->move_to_front(); + dock_slot[i]->move_child(node, 0); continue; } @@ -4914,6 +4919,7 @@ void EditorNode::_load_docks_from_config(Ref<ConfigFile> p_layout, const String dock_slot[atidx]->hide(); } dock_slot[i]->add_child(node); + dock_slot[i]->move_child(node, 0); dock_slot[i]->show(); } } @@ -5878,10 +5884,6 @@ void EditorNode::_feature_profile_changed() { node_tabs->set_tab_hidden(node_tabs->get_tab_idx_from_control(NodeDock::get_singleton()), false); fs_tabs->set_tab_hidden(fs_tabs->get_tab_idx_from_control(FileSystemDock::get_singleton()), false); history_tabs->set_tab_hidden(history_tabs->get_tab_idx_from_control(history_dock), false); - history_dock->set_visible(true); - ImportDock::get_singleton()->set_visible(true); - NodeDock::get_singleton()->set_visible(true); - FileSystemDock::get_singleton()->set_visible(true); main_editor_buttons[EDITOR_3D]->set_visible(true); main_editor_buttons[EDITOR_SCRIPT]->set_visible(true); if (AssetLibraryEditorPlugin::is_available()) { @@ -6036,14 +6038,7 @@ EditorNode::EditorNode() { Input *id = Input::get_singleton(); if (id) { - bool found_touchscreen = false; - for (int i = 0; i < DisplayServer::get_singleton()->get_screen_count(); i++) { - if (DisplayServer::get_singleton()->screen_is_touchscreen(i)) { - found_touchscreen = true; - } - } - - if (!found_touchscreen && Input::get_singleton()) { + if (!DisplayServer::get_singleton()->is_touchscreen_available() && Input::get_singleton()) { // Only if no touchscreen ui hint, disable emulation just in case. id->set_emulate_touch_from_mouse(false); } diff --git a/editor/editor_node.h b/editor/editor_node.h index ff0338a794..c430662c7f 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -32,12 +32,13 @@ #define EDITOR_NODE_H #include "core/templates/safe_refcount.h" +#include "editor/editor_data.h" #include "editor/editor_folding.h" #include "editor/editor_native_shader_source_visualizer.h" +#include "editor/editor_plugin.h" #include "editor/editor_run.h" #include "editor/editor_title_bar.h" #include "editor/export/editor_export.h" -#include "editor/inspector_dock.h" typedef void (*EditorNodeInitCallback)(); typedef void (*EditorPluginInitializeCallback)(); @@ -46,8 +47,8 @@ typedef bool (*EditorBuildCallback)(); class AcceptDialog; class AudioStreamPreviewGenerator; class BackgroundProgress; -class Button; class CenterContainer; +class CheckBox; class ColorPicker; class ConfirmationDialog; class Control; @@ -59,18 +60,19 @@ class EditorCommandPalette; class EditorExport; class EditorExtensionManager; class EditorFeatureProfileManager; +class EditorFileDialog; class EditorFileServer; class EditorFolding; class EditorInspector; class EditorLayoutsDialog; class EditorLog; -class EditorPlugin; class EditorPluginList; class EditorQuickOpen; class EditorResourcePreview; class EditorResourceConversionPlugin; class EditorRun; class EditorRunNative; +class EditorSelectionHistory; class EditorSettingsDialog; class EditorToaster; class EditorUndoRedoManager; @@ -84,6 +86,7 @@ class LinkButton; class MenuBar; class MenuButton; class NodeDock; +class OptionButton; class OrphanResourcesDialog; class Panel; class PanelContainer; @@ -98,7 +101,9 @@ class ScriptCreateDialog; class SubViewport; class TabBar; class TabContainer; +class TextureRect; class TextureProgressBar; +class Tree; class VSplitContainer; class Window; class EditorBuildProfileManager; @@ -775,7 +780,7 @@ public: bool is_movie_maker_enabled() const; void edit_node(Node *p_node); - void edit_resource(const Ref<Resource> &p_resource) { InspectorDock::get_singleton()->edit_resource(p_resource); }; + void edit_resource(const Ref<Resource> &p_resource); void save_resource_in_path(const Ref<Resource> &p_resource, const String &p_path); void save_resource(const Ref<Resource> &p_resource); diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp index e11bc3c252..f9c8b722c4 100644 --- a/editor/editor_plugin.cpp +++ b/editor/editor_plugin.cpp @@ -42,6 +42,7 @@ #include "editor/filesystem_dock.h" #include "editor/import/editor_import_plugin.h" #include "editor/import/resource_importer_scene.h" +#include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/editor_debugger_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 8c53f576ac..fb3bf46c05 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -32,16 +32,22 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" +#include "editor/create_dialog.h" #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_properties_array_dict.h" -#include "editor/editor_resource_preview.h" +#include "editor/editor_resource_picker.h" #include "editor/editor_scale.h" -#include "editor/filesystem_dock.h" +#include "editor/editor_settings.h" +#include "editor/inspector_dock.h" +#include "editor/plugins/script_editor_plugin.h" #include "editor/project_settings_editor.h" +#include "editor/property_selector.h" +#include "editor/scene_tree_editor.h" #include "scene/2d/gpu_particles_2d.h" #include "scene/3d/fog_volume.h" #include "scene/3d/gpu_particles_3d.h" +#include "scene/gui/color_picker.h" #include "scene/main/window.h" #include "scene/resources/font.h" #include "scene/resources/mesh.h" diff --git a/editor/editor_properties.h b/editor/editor_properties.h index ad36e01544..f38e33d9e3 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -31,15 +31,19 @@ #ifndef EDITOR_PROPERTIES_H #define EDITOR_PROPERTIES_H -#include "editor/create_dialog.h" #include "editor/editor_inspector.h" -#include "editor/editor_locale_dialog.h" -#include "editor/editor_resource_picker.h" -#include "editor/editor_spin_slider.h" -#include "editor/property_selector.h" -#include "editor/scene_tree_editor.h" -#include "scene/gui/color_picker.h" -#include "scene/gui/line_edit.h" + +class CheckBox; +class ColorPickerButton; +class CreateDialog; +class EditorFileDialog; +class EditorLocaleDialog; +class EditorResourcePicker; +class EditorSpinSlider; +class PropertySelector; +class SceneTreeDialog; +class TextEdit; +class TextureButton; class EditorPropertyNil : public EditorProperty { GDCLASS(EditorPropertyNil, EditorProperty); diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp index 659221ee0b..edda6c5d7b 100644 --- a/editor/editor_properties_array_dict.cpp +++ b/editor/editor_properties_array_dict.cpp @@ -34,6 +34,7 @@ #include "core/io/marshalls.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/inspector_dock.h" bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) { @@ -692,6 +693,8 @@ void EditorPropertyArray::_reorder_button_up() { reorder_mouse_y_delta = 0.0f; Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + + ERR_FAIL_NULL(reorder_selected_button); reorder_selected_button->warp_mouse(reorder_selected_button->get_size() / 2.0f); reorder_selected_element_hbox = nullptr; diff --git a/editor/editor_property_name_processor.cpp b/editor/editor_property_name_processor.cpp index bd8b753720..9587e65cad 100644 --- a/editor/editor_property_name_processor.cpp +++ b/editor/editor_property_name_processor.cpp @@ -64,8 +64,8 @@ String EditorPropertyNameProcessor::_capitalize_name(const String &p_name) const Vector<String> parts = p_name.split("_", false); for (int i = 0; i < parts.size(); i++) { - // Articles/conjunctions/prepositions which should only be capitalized if first word. - if (i != 0 && stop_words.find(parts[i]) != -1) { + // Articles/conjunctions/prepositions which should only be capitalized when not at beginning and end. + if (i > 0 && i + 1 < parts.size() && stop_words.find(parts[i]) != -1) { continue; } HashMap<String, String>::ConstIterator remap = capitalize_string_remaps.find(parts[i]); @@ -260,6 +260,8 @@ EditorPropertyNameProcessor::EditorPropertyNameProcessor() { capitalize_string_remaps["yz"] = "YZ"; // Articles, conjunctions, prepositions. + // The following initialization is parsed in `editor/translations/extract.py` with a regex. + // The word definition format should be kept synced with the regex. stop_words = LocalVector<String>({ "a", "an", diff --git a/editor/editor_quick_open.cpp b/editor/editor_quick_open.cpp index bb533b88d6..6ddccba0e2 100644 --- a/editor/editor_quick_open.cpp +++ b/editor/editor_quick_open.cpp @@ -34,23 +34,24 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" -void EditorQuickOpen::popup_dialog(const String &p_base, bool p_enable_multi, bool p_dontclear) { +static Rect2i prev_rect = Rect2i(); +static bool was_showed = false; + +void EditorQuickOpen::popup_dialog(const String &p_base, bool p_enable_multi, bool p_dont_clear) { base_type = p_base; allow_multi_select = p_enable_multi; search_options->set_select_mode(allow_multi_select ? Tree::SELECT_MULTI : Tree::SELECT_SINGLE); - static bool was_showed = false; - if (!was_showed) { - was_showed = true; - popup_centered_clamped(Size2(600, 440) * EDSCALE, 0.8f); + if (was_showed) { + popup(prev_rect); } else { - show(); + popup_centered_clamped(Size2(600, 440) * EDSCALE, 0.8f); } EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem(); _build_search_cache(efsd); - if (p_dontclear) { + if (p_dont_clear) { search_box->select_all(); _update_search(); } else { @@ -251,6 +252,13 @@ void EditorQuickOpen::_notification(int p_what) { search_box->set_clear_button_enabled(true); } break; + case NOTIFICATION_VISIBILITY_CHANGED: { + if (!is_visible()) { + prev_rect = Rect2i(get_position(), get_size()); + was_showed = true; + } + } break; + case NOTIFICATION_EXIT_TREE: { disconnect("confirmed", callable_mp(this, &EditorQuickOpen::_confirmed)); } break; diff --git a/editor/editor_run.h b/editor/editor_run.h index 4cbc6838e4..935e32ee2a 100644 --- a/editor/editor_run.h +++ b/editor/editor_run.h @@ -32,7 +32,7 @@ #define EDITOR_RUN_H #include "core/os/os.h" -#include "scene/main/node.h" + class EditorRun { public: enum Status { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index bc186c7a16..c44fe04442 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -452,11 +452,12 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/inspector/show_low_level_opentype_features", false, "") // Theme - EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Custom") + EDITOR_SETTING(Variant::STRING, PROPERTY_HINT_ENUM, "interface/theme/preset", "Default", "Default,Breeze Dark,Godot 2,Gray,Light,Solarized (Dark),Solarized (Light),Black (OLED),Custom") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/theme/icon_and_font_color", 0, "Auto,Dark,Light") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/base_color", Color(0.2, 0.23, 0.31), "") EDITOR_SETTING(Variant::COLOR, PROPERTY_HINT_NONE, "interface/theme/accent_color", Color(0.41, 0.61, 0.91), "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/contrast", 0.3, "-1,1,0.01") + EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/theme/draw_extra_borders", false, "") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/icon_saturation", 1.0, "0,2,0.01") EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/theme/relationship_line_opacity", 0.1, "0.00,1,0.01") EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "interface/theme/border_size", 0, "0,2,1") diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp index b1b54fd717..6c11572d10 100644 --- a/editor/editor_settings_dialog.cpp +++ b/editor/editor_settings_dialog.cpp @@ -61,7 +61,7 @@ void EditorSettingsDialog::_settings_changed() { void EditorSettingsDialog::_settings_property_edited(const String &p_name) { String full_name = inspector->get_full_item_path(p_name); - if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast") { + if (full_name == "interface/theme/accent_color" || full_name == "interface/theme/base_color" || full_name == "interface/theme/contrast" || full_name == "interface/theme/draw_extra_borders") { EditorSettings::get_singleton()->set_manually("interface/theme/preset", "Custom"); // set preset to Custom } else if (full_name.begins_with("text_editor/theme/highlighting")) { EditorSettings::get_singleton()->set_manually("text_editor/theme/color_theme", "Custom"); diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 11a8fce9c3..9128143619 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -582,6 +582,7 @@ void EditorSpinSlider::_value_focus_exited() { //tab was pressed } else { //enter, click, esc + grab_focus(); } } diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index df28b2e6ab..96834f4a6c 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -393,6 +393,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color accent_color = EDITOR_GET("interface/theme/accent_color"); Color base_color = EDITOR_GET("interface/theme/base_color"); float contrast = EDITOR_GET("interface/theme/contrast"); + bool draw_extra_borders = EDITOR_GET("interface/theme/draw_extra_borders"); float icon_saturation = EDITOR_GET("interface/theme/icon_saturation"); float relationship_line_opacity = EDITOR_GET("interface/theme/relationship_line_opacity"); @@ -404,6 +405,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color preset_accent_color; Color preset_base_color; float preset_contrast = 0; + bool preset_draw_extra_borders = false; const float default_contrast = 0.3; @@ -440,6 +442,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { preset_base_color = Color(0.89, 0.86, 0.79); // A negative contrast rate looks better for light themes, since it better follows the natural order of UI "elevation". preset_contrast = -0.08; + } else if (preset == "Black (OLED)") { + preset_accent_color = Color(0.45, 0.75, 1.0); + preset_base_color = Color(0, 0, 0); + // The contrast rate value is irrelevant on a fully black theme. + preset_contrast = 0.0; + preset_draw_extra_borders = true; } else { // Default preset_accent_color = Color(0.44, 0.73, 0.98); preset_base_color = Color(0.21, 0.24, 0.29); @@ -450,15 +458,18 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { accent_color = preset_accent_color; base_color = preset_base_color; contrast = preset_contrast; + draw_extra_borders = preset_draw_extra_borders; EditorSettings::get_singleton()->set_initial_value("interface/theme/accent_color", accent_color); EditorSettings::get_singleton()->set_initial_value("interface/theme/base_color", base_color); EditorSettings::get_singleton()->set_initial_value("interface/theme/contrast", contrast); + EditorSettings::get_singleton()->set_initial_value("interface/theme/draw_extra_borders", draw_extra_borders); } EditorSettings::get_singleton()->set_manually("interface/theme/preset", preset); EditorSettings::get_singleton()->set_manually("interface/theme/accent_color", accent_color); EditorSettings::get_singleton()->set_manually("interface/theme/base_color", base_color); EditorSettings::get_singleton()->set_manually("interface/theme/contrast", contrast); + EditorSettings::get_singleton()->set_manually("interface/theme/draw_extra_borders", draw_extra_borders); // Colors bool dark_theme = EditorSettings::get_singleton()->is_dark_theme(); @@ -477,6 +488,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color dark_color_2 = base_color.lerp(Color(0, 0, 0, 1), contrast * 1.5).clamp(); const Color dark_color_3 = base_color.lerp(Color(0, 0, 0, 1), contrast * 2).clamp(); + // Only used when the Draw Extra Borders editor setting is enabled. + const Color extra_border_color_1 = Color(0.5, 0.5, 0.5); + const Color extra_border_color_2 = dark_theme ? Color(0.3, 0.3, 0.3) : Color(0.7, 0.7, 0.7); + const Color background_color = dark_color_2; // White (dark theme) or black (light theme), will be used to generate the rest of the colors @@ -489,7 +504,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const Color font_hover_color = mono_color.lerp(base_color, 0.125); const Color font_focus_color = mono_color.lerp(base_color, 0.125); const Color font_hover_pressed_color = font_hover_color.lerp(accent_color, 0.74); - const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.3); + const Color font_disabled_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.35); const Color font_readonly_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.65); const Color font_placeholder_color = Color(mono_color.r, mono_color.g, mono_color.b, 0.6); const Color selection_color = accent_color * Color(1, 1, 1, 0.4); @@ -634,10 +649,19 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_widget = style_default->duplicate(); style_widget->set_default_margin_individual(widget_default_margin.x, widget_default_margin.y, widget_default_margin.x, widget_default_margin.y); style_widget->set_bg_color(dark_color_1); - style_widget->set_border_color(dark_color_2); + if (draw_extra_borders) { + style_widget->set_border_width_all(Math::round(EDSCALE)); + style_widget->set_border_color(extra_border_color_1); + } else { + style_widget->set_border_color(dark_color_2); + } Ref<StyleBoxFlat> style_widget_disabled = style_widget->duplicate(); - style_widget_disabled->set_border_color(disabled_color); + if (draw_extra_borders) { + style_widget_disabled->set_border_color(extra_border_color_2); + } else { + style_widget_disabled->set_border_color(disabled_color); + } style_widget_disabled->set_bg_color(disabled_bg_color); Ref<StyleBoxFlat> style_widget_focus = style_widget->duplicate(); @@ -650,7 +674,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_widget_hover = style_widget->duplicate(); style_widget_hover->set_bg_color(mono_color * Color(1, 1, 1, 0.11)); - style_widget_hover->set_border_color(mono_color * Color(1, 1, 1, 0.05)); + if (draw_extra_borders) { + style_widget_hover->set_border_color(extra_border_color_1); + } else { + style_widget_hover->set_border_color(mono_color * Color(1, 1, 1, 0.05)); + } // Style for windows, popups, etc.. Ref<StyleBoxFlat> style_popup = style_default->duplicate(); @@ -991,7 +1019,11 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { style_popup_menu->set_default_margin_individual(EDSCALE, 2 * EDSCALE, EDSCALE, 2 * EDSCALE); // Always display a border for PopupMenus so they can be distinguished from their background. style_popup_menu->set_border_width_all(EDSCALE); - style_popup_menu->set_border_color(dark_color_2); + if (draw_extra_borders) { + style_popup_menu->set_border_color(extra_border_color_2); + } else { + style_popup_menu->set_border_color(dark_color_2); + } theme->set_stylebox("panel", "PopupMenu", style_popup_menu); Ref<StyleBoxFlat> style_menu_hover = style_widget_hover->duplicate(); @@ -1111,7 +1143,13 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Ref<StyleBoxFlat> style_tree_bg = style_default->duplicate(); // Make Trees easier to distinguish from other controls by using a darker background color. style_tree_bg->set_bg_color(dark_color_1.lerp(dark_color_2, 0.5)); - style_tree_bg->set_border_color(dark_color_3); + if (draw_extra_borders) { + style_tree_bg->set_border_width_all(Math::round(EDSCALE)); + style_tree_bg->set_border_color(extra_border_color_2); + } else { + style_tree_bg->set_border_color(dark_color_3); + } + theme->set_stylebox("panel", "Tree", style_tree_bg); // Tree @@ -1207,8 +1245,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // ItemList Ref<StyleBoxFlat> style_itemlist_bg = style_default->duplicate(); style_itemlist_bg->set_bg_color(dark_color_1); - style_itemlist_bg->set_border_width_all(border_width); - style_itemlist_bg->set_border_color(dark_color_3); + + if (draw_extra_borders) { + style_itemlist_bg->set_border_width_all(Math::round(EDSCALE)); + style_itemlist_bg->set_border_color(extra_border_color_2); + } else { + style_itemlist_bg->set_border_width_all(border_width); + style_itemlist_bg->set_border_color(dark_color_3); + } Ref<StyleBoxFlat> style_itemlist_cursor = style_default->duplicate(); style_itemlist_cursor->set_draw_center(false); @@ -1326,14 +1370,21 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // The original style_widget style has an extra 1 pixel offset that makes LineEdits not align with Buttons, // so this compensates for that. style_line_edit->set_default_margin(SIDE_TOP, style_line_edit->get_default_margin(SIDE_TOP) - 1 * EDSCALE); - // Add a bottom line to make LineEdits more visible, especially in sectioned inspectors - // such as the Project Settings. - style_line_edit->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); - style_line_edit->set_border_color(dark_color_2); + // Don't round the bottom corner to make the line look sharper. style_tab_selected->set_corner_radius(CORNER_BOTTOM_LEFT, 0); style_tab_selected->set_corner_radius(CORNER_BOTTOM_RIGHT, 0); + if (draw_extra_borders) { + style_line_edit->set_border_width_all(Math::round(EDSCALE)); + style_line_edit->set_border_color(extra_border_color_1); + } else { + // Add a bottom line to make LineEdits more visible, especially in sectioned inspectors + // such as the Project Settings. + style_line_edit->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE)); + style_line_edit->set_border_color(dark_color_2); + } + Ref<StyleBoxFlat> style_line_edit_disabled = style_line_edit->duplicate(); style_line_edit_disabled->set_border_color(disabled_color); style_line_edit_disabled->set_bg_color(disabled_bg_color); diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp index 7c5c7da2ef..d0dcbc3bfd 100644 --- a/editor/export/editor_export_platform.cpp +++ b/editor/export/editor_export_platform.cpp @@ -32,7 +32,7 @@ #include "core/config/project_settings.h" #include "core/crypto/crypto_core.h" -#include "core/extension/native_extension.h" +#include "core/extension/gdextension.h" #include "core/io/file_access_encrypted.h" #include "core/io/file_access_pack.h" // PACK_HEADER_MAGIC, PACK_FORMAT_VERSION #include "core/io/zip_io.h" @@ -442,10 +442,11 @@ HashSet<String> EditorExportPlatform::get_features(const Ref<EditorExportPreset> result.insert(E); } + result.insert("template"); if (p_debug) { - result.insert("debug"); + result.insert("template_debug"); } else { - result.insert("release"); + result.insert("template_release"); } if (!p_preset->get_custom_features().is_empty()) { @@ -1034,7 +1035,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & return err; } // Now actual remapped file: - sarr = FileAccess::get_file_as_array(export_path); + sarr = FileAccess::get_file_as_bytes(export_path); err = p_func(p_udata, export_path, sarr, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1053,7 +1054,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & if (importer_type == "keep") { //just keep file as-is - Vector<uint8_t> array = FileAccess::get_file_as_array(path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(path); err = p_func(p_udata, path, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { @@ -1086,14 +1087,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String remap = F; if (remap == "path") { String remapped_path = config->get_value("remap", remap); - Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path); err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); } else if (remap.begins_with("path.")) { String feature = remap.get_slice(".", 1); if (remap_features.has(feature)) { String remapped_path = config->get_value("remap", remap); - Vector<uint8_t> array = FileAccess::get_file_as_array(remapped_path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(remapped_path); err = p_func(p_udata, remapped_path, array, idx, total, enc_in_filters, enc_ex_filters, key); } } @@ -1104,7 +1105,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } //also save the .import file - Vector<uint8_t> array = FileAccess::get_file_as_array(path + ".import"); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(path + ".import"); err = p_func(p_udata, path + ".import", array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { @@ -1164,7 +1165,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & path_remaps.push_back(export_path); } - Vector<uint8_t> array = FileAccess::get_file_as_array(export_path); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(export_path); err = p_func(p_udata, export_path, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1244,14 +1245,14 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String icon = GLOBAL_GET("application/config/icon"); String splash = GLOBAL_GET("application/boot_splash/image"); if (!icon.is_empty() && FileAccess::exists(icon)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(icon); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(icon); err = p_func(p_udata, icon, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; } } if (!splash.is_empty() && FileAccess::exists(splash) && icon != splash) { - Vector<uint8_t> array = FileAccess::get_file_as_array(splash); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(splash); err = p_func(p_udata, splash, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1259,16 +1260,16 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & } String resource_cache_file = ResourceUID::get_cache_file(); if (FileAccess::exists(resource_cache_file)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(resource_cache_file); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(resource_cache_file); err = p_func(p_udata, resource_cache_file, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; } } - String extension_list_config_file = NativeExtension::get_extension_list_config_file(); + String extension_list_config_file = GDExtension::get_extension_list_config_file(); if (FileAccess::exists(extension_list_config_file)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(extension_list_config_file); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(extension_list_config_file); err = p_func(p_udata, extension_list_config_file, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1282,7 +1283,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & // Try using user provided data file. String ts_data = "res://" + TS->get_support_data_filename(); if (FileAccess::exists(ts_data)) { - Vector<uint8_t> array = FileAccess::get_file_as_array(ts_data); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(ts_data); err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key); if (err != OK) { return err; @@ -1291,7 +1292,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & // Use default text server data. String icu_data_file = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp_icu_data"); TS->save_support_data(icu_data_file); - Vector<uint8_t> array = FileAccess::get_file_as_array(icu_data_file); + Vector<uint8_t> array = FileAccess::get_file_as_bytes(icu_data_file); err = p_func(p_udata, ts_data, array, idx, total, enc_in_filters, enc_ex_filters, key); DirAccess::remove_file_or_error(icu_data_file); if (err != OK) { @@ -1304,7 +1305,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String config_file = "project.binary"; String engine_cfb = EditorPaths::get_singleton()->get_cache_dir().path_join("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); - Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(engine_cfb); DirAccess::remove_file_or_error(engine_cfb); return p_func(p_udata, "res://" + config_file, data, idx, total, enc_in_filters, enc_ex_filters, key); diff --git a/editor/export/editor_export_plugin.cpp b/editor/export/editor_export_plugin.cpp index 78d4f93dfe..f0e841f307 100644 --- a/editor/export/editor_export_plugin.cpp +++ b/editor/export/editor_export_plugin.cpp @@ -148,10 +148,8 @@ bool EditorExportPlugin::_begin_customize_resources(const Ref<EditorExportPlatfo Ref<Resource> EditorExportPlugin::_customize_resource(const Ref<Resource> &p_resource, const String &p_path) { Ref<Resource> ret; - if (GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret)) { - return ret; - } - return Ref<Resource>(); + GDVIRTUAL_REQUIRED_CALL(_customize_resource, p_resource, p_path, ret); + return ret; } bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> &p_platform, const Vector<String> &p_features) const { @@ -162,18 +160,14 @@ bool EditorExportPlugin::_begin_customize_scenes(const Ref<EditorExportPlatform> Node *EditorExportPlugin::_customize_scene(Node *p_root, const String &p_path) { Node *ret = nullptr; - if (GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret)) { - return ret; - } - return nullptr; + GDVIRTUAL_REQUIRED_CALL(_customize_scene, p_root, p_path, ret); + return ret; } uint64_t EditorExportPlugin::_get_customization_configuration_hash() const { uint64_t ret = 0; - if (GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret)) { - return ret; - } - return 0; + GDVIRTUAL_REQUIRED_CALL(_get_customization_configuration_hash, ret); + return ret; } void EditorExportPlugin::_end_customize_scenes() { @@ -186,10 +180,8 @@ void EditorExportPlugin::_end_customize_resources() { String EditorExportPlugin::_get_name() const { String ret; - if (GDVIRTUAL_REQUIRED_CALL(_get_name, ret)) { - return ret; - } - return ""; + GDVIRTUAL_REQUIRED_CALL(_get_name, ret); + return ret; } void EditorExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) { diff --git a/editor/export/editor_export_plugin.h b/editor/export/editor_export_plugin.h index 3f37ed40be..88eeaf821d 100644 --- a/editor/export/editor_export_plugin.h +++ b/editor/export/editor_export_plugin.h @@ -31,7 +31,7 @@ #ifndef EDITOR_EXPORT_PLUGIN_H #define EDITOR_EXPORT_PLUGIN_H -#include "core/extension/native_extension.h" +#include "core/extension/gdextension.h" #include "editor_export_preset.h" #include "editor_export_shared_object.h" #include "scene/main/node.h" diff --git a/editor/export/export_template_manager.cpp b/editor/export/export_template_manager.cpp index 9ebf4d795a..84766a5bef 100644 --- a/editor/export/export_template_manager.cpp +++ b/editor/export/export_template_manager.cpp @@ -40,6 +40,7 @@ #include "editor/editor_settings.h" #include "editor/progress_dialog.h" #include "scene/gui/file_dialog.h" +#include "scene/gui/menu_button.h" #include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/main/http_request.h" diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp index 6ff3539708..f5c5aafb5d 100644 --- a/editor/export/project_export.cpp +++ b/editor/export/project_export.cpp @@ -37,9 +37,16 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/export/editor_export.h" +#include "scene/gui/check_box.h" #include "scene/gui/check_button.h" +#include "scene/gui/item_list.h" #include "scene/gui/link_button.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" void ProjectExportDialog::_theme_changed() { diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 8df5808b11..6316a7f545 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1414,7 +1414,7 @@ void FileSystemDock::_update_dependencies_after_move(const HashMap<String, Strin Error err = ResourceLoader::rename_dependencies(file, p_renames); if (err == OK) { if (ResourceLoader::get_resource_type(file) == "PackedScene") { - EditorNode::get_singleton()->reload_scene(file); + callable_mp(EditorNode::get_singleton(), &EditorNode::reload_scene).bind(file).call_deferred(); } } else { EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies:") + "\n" + remaps[i] + "\n"); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 666444eaf9..b7e7200b11 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -769,7 +769,7 @@ void FindInFilesPanel::draw_result_text(Object *item_obj, Rect2 rect) { Rect2 match_rect = rect; match_rect.position.x += font->get_string_size(item_text.left(r.begin_trimmed), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x - 1; - match_rect.size.x = font->get_string_size(_search_text_label->get_text(), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + 2; + match_rect.size.x = font->get_string_size(_search_text_label->get_text(), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + 1; match_rect.position.y += 1 * EDSCALE; match_rect.size.y -= 2 * EDSCALE; diff --git a/editor/icons/OneWayTile.svg b/editor/icons/OneWayTile.svg new file mode 100644 index 0000000000..273b1a183b --- /dev/null +++ b/editor/icons/OneWayTile.svg @@ -0,0 +1 @@ +<svg clip-rule="evenodd" fill-rule="evenodd" height="16" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m10.958984 1.5-1.4785152 1.4667969-1.4785157 1.46875-1.4804687-1.4667969-1.4785156-1.4667969-.5214844.5136719-.5214844.5136719 2 1.9863281 2 1.984375 2-1.984375 2-1.9824219-.519531-.5175781zm0 8-1.4785152 1.466797-1.4785157 1.46875-1.4804687-1.466797-1.4785156-1.4667969-.5214844.5136719-.5214844.513672 2 1.986328 2 1.984375 2-1.984375 2-1.982422-.519531-.517578z" fill="#fff"/></svg> diff --git a/editor/icons/TileSelection.svg b/editor/icons/TileSelection.svg new file mode 100644 index 0000000000..418382aa1c --- /dev/null +++ b/editor/icons/TileSelection.svg @@ -0,0 +1,57 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + height="5" + viewBox="0 0 5 5" + width="5" + version="1.1" + id="svg10" + sodipodi:docname="TileSelection.svg" + inkscape:version="1.1 (c68e22c387, 2021-05-23)" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg"> + <defs + id="defs14"> + <linearGradient + id="linearGradient1060" + inkscape:swatch="solid"> + <stop + style="stop-color:#000000;stop-opacity:1;" + offset="0" + id="stop1058" /> + </linearGradient> + </defs> + <sodipodi:namedview + id="namedview12" + pagecolor="#505050" + bordercolor="#ffffff" + borderopacity="1" + inkscape:pageshadow="0" + inkscape:pageopacity="0" + inkscape:pagecheckerboard="1" + showgrid="false" + inkscape:zoom="64" + inkscape:cx="4.3125" + inkscape:cy="1.984375" + inkscape:window-width="3840" + inkscape:window-height="2066" + inkscape:window-x="-11" + inkscape:window-y="-11" + inkscape:window-maximized="1" + inkscape:current-layer="svg10" /> + <rect + style="fill:none;stroke:#ffffff;stroke-width:1.00038;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect940" + width="3.9996195" + height="3.999619" + x="0.50019002" + y="0.50019002" /> + <rect + style="fill:none;stroke:#000000;stroke-width:0.999543;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1" + id="rect3062" + width="2.000457" + height="2.000457" + x="1.4997715" + y="1.4997715" /> +</svg> diff --git a/editor/icons/TrackTrigger.svg b/editor/icons/TrackTrigger.svg deleted file mode 100644 index c403fba59a..0000000000 --- a/editor/icons/TrackTrigger.svg +++ /dev/null @@ -1 +0,0 @@ -<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/dynamic_font_import_settings.cpp b/editor/import/dynamic_font_import_settings.cpp index 8f15becd95..afcfacdf75 100644 --- a/editor/import/dynamic_font_import_settings.cpp +++ b/editor/import/dynamic_font_import_settings.cpp @@ -469,6 +469,8 @@ void DynamicFontImportSettings::_main_prop_changed(const String &p_edited_proper font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); } else if (p_edited_property == "msdf_size") { font_preview->set_msdf_size(import_settings_data->get("msdf_size")); + } else if (p_edited_property == "allow_system_fallback") { + font_preview->set_allow_system_fallback(import_settings_data->get("allow_system_fallback")); } else if (p_edited_property == "force_autohinter") { font_preview->set_force_autohinter(import_settings_data->get("force_autohinter")); } else if (p_edited_property == "hinting") { @@ -936,6 +938,7 @@ void DynamicFontImportSettings::_re_import() { main_settings["multichannel_signed_distance_field"] = import_settings_data->get("multichannel_signed_distance_field"); main_settings["msdf_pixel_range"] = import_settings_data->get("msdf_pixel_range"); main_settings["msdf_size"] = import_settings_data->get("msdf_size"); + main_settings["allow_system_fallback"] = import_settings_data->get("allow_system_fallback"); main_settings["force_autohinter"] = import_settings_data->get("force_autohinter"); main_settings["hinting"] = import_settings_data->get("hinting"); main_settings["subpixel_positioning"] = import_settings_data->get("subpixel_positioning"); @@ -951,9 +954,18 @@ void DynamicFontImportSettings::_re_import() { Dictionary preload_config; preload_config["name"] = vars_item->get_text(0); + Size2i conf_size = Vector2i(16, 0); for (const KeyValue<StringName, Variant> &E : import_variation_data->settings) { - preload_config[E.key] = E.value; + if (E.key == "size") { + conf_size.x = E.value; + } + if (E.key == "outline_size") { + conf_size.y = E.value; + } else { + preload_config[E.key] = E.value; + } } + preload_config["size"] = conf_size; Array chars; for (const char32_t &E : import_variation_data->selected_chars) { @@ -1036,7 +1048,7 @@ void DynamicFontImportSettings::_process_locales() { void DynamicFontImportSettings::open_settings(const String &p_path) { // Load base font data. - Vector<uint8_t> font_data = FileAccess::get_file_as_array(p_path); + Vector<uint8_t> font_data = FileAccess::get_file_as_bytes(p_path); // Load project locale list. locale_tree->clear(); @@ -1202,6 +1214,7 @@ void DynamicFontImportSettings::open_settings(const String &p_path) { font_preview->set_multichannel_signed_distance_field(import_settings_data->get("multichannel_signed_distance_field")); font_preview->set_msdf_pixel_range(import_settings_data->get("msdf_pixel_range")); font_preview->set_msdf_size(import_settings_data->get("msdf_size")); + font_preview->set_allow_system_fallback(import_settings_data->get("allow_system_fallback")); font_preview->set_force_autohinter(import_settings_data->get("force_autohinter")); font_preview->set_hinting((TextServer::Hinting)import_settings_data->get("hinting").operator int()); font_preview->set_subpixel_positioning((TextServer::SubpixelPositioning)import_settings_data->get("subpixel_positioning").operator int()); @@ -1232,6 +1245,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "multichannel_signed_distance_field", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48)); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), 1)); @@ -1243,7 +1257,7 @@ DynamicFontImportSettings::DynamicFontImportSettings() { options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::DICTIONARY, "opentype_features"), Dictionary())); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); - options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); + options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), Array())); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::NIL, "Compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); options_general.push_back(ResourceImporter::ImportOption(PropertyInfo(Variant::BOOL, "compress", PROPERTY_HINT_NONE, ""), false)); diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 6890a46193..c335655d4e 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -65,7 +65,7 @@ struct ColladaImport { bool force_make_tangents = false; bool apply_mesh_xform_to_vertices = true; bool use_mesh_builtin_materials = false; - float bake_fps = 15; + float bake_fps = 30; HashMap<String, NodeMap> node_map; //map from collada node to engine node HashMap<String, String> node_name_map; //map from collada node to engine node @@ -1760,7 +1760,7 @@ void EditorSceneFormatImporterCollada::get_extensions(List<String> *r_extensions r_extensions->push_back("dae"); } -Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { if (r_err) { *r_err = OK; } @@ -1771,7 +1771,7 @@ Node *EditorSceneFormatImporterCollada::import_scene(const String &p_path, uint3 } state.use_mesh_builtin_materials = true; - state.bake_fps = p_bake_fps; + state.bake_fps = (float)p_options["animation/fps"]; Error err = state.load(p_path, flags, p_flags & EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, false); diff --git a/editor/import/editor_import_collada.h b/editor/import/editor_import_collada.h index a75b0a903f..ec30c91c1b 100644 --- a/editor/import/editor_import_collada.h +++ b/editor/import/editor_import_collada.h @@ -39,7 +39,7 @@ class EditorSceneFormatImporterCollada : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps = nullptr, Error *r_err = nullptr) override; EditorSceneFormatImporterCollada(); }; diff --git a/editor/import/resource_importer_bmfont.cpp b/editor/import/resource_importer_bmfont.cpp index 14b5638755..357faf0022 100644 --- a/editor/import/resource_importer_bmfont.cpp +++ b/editor/import/resource_importer_bmfont.cpp @@ -60,7 +60,7 @@ bool ResourceImporterBMFont::get_option_visibility(const String &p_path, const S } void ResourceImporterBMFont::get_import_options(const String &p_path, List<ImportOption> *r_options, int p_preset) const { - r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), Array())); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); } @@ -76,6 +76,7 @@ Error ResourceImporterBMFont::import(const String &p_source_file, const String & Error err = font->load_bitmap_font(p_source_file); ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load font to file \"" + p_source_file + "\"."); + font->set_allow_system_fallback(false); font->set_fallbacks(fallbacks); int flg = 0; diff --git a/editor/import/resource_importer_dynamic_font.cpp b/editor/import/resource_importer_dynamic_font.cpp index a6ae832479..2f1445af48 100644 --- a/editor/import/resource_importer_dynamic_font.cpp +++ b/editor/import/resource_importer_dynamic_font.cpp @@ -114,13 +114,14 @@ void ResourceImporterDynamicFont::get_import_options(const String &p_path, List< r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_pixel_range", PROPERTY_HINT_RANGE, "1,100,1"), 8)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "msdf_size", PROPERTY_HINT_RANGE, "1,250,1"), 48)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "allow_system_fallback"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "force_autohinter"), false)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "hinting", PROPERTY_HINT_ENUM, "None,Light,Normal"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::INT, "subpixel_positioning", PROPERTY_HINT_ENUM, "Disabled,Auto,One Half of a Pixel,One Quarter of a Pixel"), 1)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "oversampling", PROPERTY_HINT_RANGE, "0,10,0.1"), 0.0)); r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Fallbacks", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); - r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), Array())); r_options->push_back(ImportOption(PropertyInfo(Variant::NIL, "Compress", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_GROUP), Variant())); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); @@ -150,13 +151,14 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str Dictionary ot_ov = p_options["opentype_features"]; bool autohinter = p_options["force_autohinter"]; + bool allow_system_fallback = p_options["allow_system_fallback"]; int hinting = p_options["hinting"]; int subpixel_positioning = p_options["subpixel_positioning"]; real_t oversampling = p_options["oversampling"]; Array fallbacks = p_options["fallbacks"]; // Load base font data. - Vector<uint8_t> data = FileAccess::get_file_as_array(p_source_file); + Vector<uint8_t> data = FileAccess::get_file_as_bytes(p_source_file); // Create font. Ref<FontFile> font; @@ -170,6 +172,7 @@ Error ResourceImporterDynamicFont::import(const String &p_source_file, const Str font->set_opentype_feature_overrides(ot_ov); font->set_fixed_size(0); font->set_force_autohinter(autohinter); + font->set_allow_system_fallback(allow_system_fallback); font->set_subpixel_positioning((TextServer::SubpixelPositioning)subpixel_positioning); font->set_hinting((TextServer::Hinting)hinting); font->set_oversampling(oversampling); diff --git a/editor/import/resource_importer_imagefont.cpp b/editor/import/resource_importer_imagefont.cpp index 9d15854707..9c3304d946 100644 --- a/editor/import/resource_importer_imagefont.cpp +++ b/editor/import/resource_importer_imagefont.cpp @@ -66,7 +66,7 @@ void ResourceImporterImageFont::get_import_options(const String &p_path, List<Im r_options->push_back(ImportOption(PropertyInfo(Variant::RECT2I, "image_margin"), Rect2i())); r_options->push_back(ImportOption(PropertyInfo(Variant::RECT2I, "character_margin"), Rect2i())); - r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, vformat("%s/%s:%s", Variant::OBJECT, PROPERTY_HINT_RESOURCE_TYPE, "Font")), Array())); + r_options->push_back(ImportOption(PropertyInfo(Variant::ARRAY, "fallbacks", PROPERTY_HINT_ARRAY_TYPE, MAKE_RESOURCE_TYPE_HINT("Font")), Array())); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "compress"), true)); } @@ -121,6 +121,7 @@ Error ResourceImporterImageFont::import(const String &p_source_file, const Strin font->set_fixed_size(chr_height); font->set_subpixel_positioning(TextServer::SUBPIXEL_POSITIONING_DISABLED); font->set_force_autohinter(false); + font->set_allow_system_fallback(false); font->set_hinting(TextServer::HINTING_NONE); font->set_oversampling(1.0f); font->set_fallbacks(fallbacks); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index fe70fd58b5..f19b4dbe56 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -422,7 +422,7 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_ return OK; } -Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { List<Ref<Mesh>> meshes; Error err = _parse_obj(p_path, meshes, false, p_flags & IMPORT_GENERATE_TANGENT_ARRAYS, false, Vector3(1, 1, 1), Vector3(0, 0, 0), r_missing_deps); diff --git a/editor/import/resource_importer_obj.h b/editor/import/resource_importer_obj.h index 4dfac90fa1..121d8e6d36 100644 --- a/editor/import/resource_importer_obj.h +++ b/editor/import/resource_importer_obj.h @@ -39,7 +39,7 @@ class EditorOBJImporter : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; EditorOBJImporter(); }; diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp index f7a3ce2679..9566c1b23c 100644 --- a/editor/import/resource_importer_scene.cpp +++ b/editor/import/resource_importer_scene.cpp @@ -74,13 +74,13 @@ void EditorSceneFormatImporter::get_extensions(List<String> *r_extensions) const ERR_FAIL(); } -Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporter::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { Dictionary options_dict; for (const KeyValue<StringName, Variant> &elem : p_options) { options_dict[elem.key] = elem.value; } Object *ret = nullptr; - if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, p_bake_fps, ret)) { + if (GDVIRTUAL_CALL(_import_scene, p_path, p_flags, options_dict, ret)) { return Object::cast_to<Node>(ret); } @@ -100,7 +100,7 @@ Variant EditorSceneFormatImporter::get_option_visibility(const String &p_path, b void EditorSceneFormatImporter::_bind_methods() { GDVIRTUAL_BIND(_get_import_flags); GDVIRTUAL_BIND(_get_extensions); - GDVIRTUAL_BIND(_import_scene, "path", "flags", "options", "bake_fps"); + GDVIRTUAL_BIND(_import_scene, "path", "flags", "options"); GDVIRTUAL_BIND(_get_import_options, "path"); GDVIRTUAL_BIND(_get_option_visibility, "path", "for_animation", "option"); @@ -355,7 +355,7 @@ static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value"); ERR_FAIL_NULL_MSG(mesh->get_mesh(), "Cannot generate shape list with null mesh value"); if (!p_convex) { - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); r_shape_list.push_back(shape); } else { Vector<Ref<Shape3D>> cd; @@ -1864,6 +1864,7 @@ void ResourceImporterScene::get_import_options(const String &p_path, List<Import r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "skins/use_named_skins"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/import"), true)); r_options->push_back(ImportOption(PropertyInfo(Variant::FLOAT, "animation/fps", PROPERTY_HINT_RANGE, "1,120,1"), 30)); + r_options->push_back(ImportOption(PropertyInfo(Variant::BOOL, "animation/trimming"), false)); 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_NO_EDITOR), Dictionary())); @@ -2281,13 +2282,8 @@ Node *ResourceImporterScene::pre_import(const String &p_source_file, const HashM ERR_FAIL_COND_V(!importer.is_valid(), nullptr); - int bake_fps = 30; - if (p_options.has(SNAME("animation/fps"))) { - bake_fps = p_options[SNAME("animation/fps")]; - } - Error err = OK; - Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_options, bake_fps, nullptr, &err); + Node *scene = importer->import_scene(p_source_file, EditorSceneFormatImporter::IMPORT_ANIMATION | EditorSceneFormatImporter::IMPORT_GENERATE_TANGENT_ARRAYS, p_options, nullptr, &err); if (!scene || err != OK) { return nullptr; } @@ -2326,8 +2322,6 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p ERR_FAIL_COND_V(!importer.is_valid(), ERR_FILE_UNRECOGNIZED); - float fps = p_options["animation/fps"]; - int import_flags = 0; if (animation_importer) { @@ -2350,7 +2344,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Error err = OK; List<String> missing_deps; // for now, not much will be done with this - Node *scene = importer->import_scene(src_path, import_flags, p_options, fps, &missing_deps, &err); + Node *scene = importer->import_scene(src_path, import_flags, p_options, &missing_deps, &err); if (!scene || err != OK) { return err; } @@ -2398,6 +2392,10 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p post_importer_plugins.write[i]->pre_process(scene, p_options); } + float fps = 30; + if (p_options.has(SNAME("animation/fps"))) { + fps = (float)p_options[SNAME("animation/fps")]; + } _pre_fix_animations(scene, scene, node_data, animation_data, fps); _post_fix_node(scene, scene, collision_map, occluder_arrays, scanned_meshes, node_data, material_data, animation_data, fps); _post_fix_animations(scene, scene, node_data, animation_data, fps); @@ -2450,7 +2448,7 @@ Error ResourceImporterScene::import(const String &p_source_file, const String &p Vector<Vector<uint8_t>> mesh_lightmap_caches; { - src_lightmap_cache = FileAccess::get_file_as_array(p_source_file + ".unwrap_cache", &err); + src_lightmap_cache = FileAccess::get_file_as_bytes(p_source_file + ".unwrap_cache", &err); if (err != OK) { src_lightmap_cache.clear(); } @@ -2612,7 +2610,7 @@ void EditorSceneFormatImporterESCN::get_extensions(List<String> *r_extensions) c r_extensions->push_back("escn"); } -Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err) { +Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err) { Error error; Ref<PackedScene> ps = ResourceFormatLoaderText::singleton->load(p_path, p_path, &error); ERR_FAIL_COND_V_MSG(!ps.is_valid(), nullptr, "Cannot load scene as text resource from path '" + p_path + "'."); diff --git a/editor/import/resource_importer_scene.h b/editor/import/resource_importer_scene.h index 5f64330453..678251372b 100644 --- a/editor/import/resource_importer_scene.h +++ b/editor/import/resource_importer_scene.h @@ -53,12 +53,12 @@ class EditorSceneFormatImporter : public RefCounted { protected: static void _bind_methods(); - Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); - Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options, int p_bake_fps); + Node *import_scene_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); + Ref<Animation> import_animation_wrapper(const String &p_path, uint32_t p_flags, Dictionary p_options); GDVIRTUAL0RC(int, _get_import_flags) GDVIRTUAL0RC(Vector<String>, _get_extensions) - GDVIRTUAL4R(Object *, _import_scene, String, uint32_t, Dictionary, uint32_t) + GDVIRTUAL3R(Object *, _import_scene, String, uint32_t, Dictionary) GDVIRTUAL1(_get_import_options, String) GDVIRTUAL3RC(Variant, _get_option_visibility, String, bool, String) @@ -74,7 +74,7 @@ public: virtual uint32_t get_import_flags() const; virtual void get_extensions(List<String> *r_extensions) const; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr); + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr); virtual void get_import_options(const String &p_path, List<ResourceImporter::ImportOption> *r_options); virtual Variant get_option_visibility(const String &p_path, bool p_for_animation, const String &p_option, const HashMap<StringName, Variant> &p_options); @@ -310,7 +310,7 @@ class EditorSceneFormatImporterESCN : public EditorSceneFormatImporter { public: virtual uint32_t get_import_flags() const override; virtual void get_extensions(List<String> *r_extensions) const override; - virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, int p_bake_fps, List<String> *r_missing_deps, Error *r_err = nullptr) override; + virtual Node *import_scene(const String &p_path, uint32_t p_flags, const HashMap<StringName, Variant> &p_options, List<String> *r_missing_deps, Error *r_err = nullptr) override; }; template <class M> diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp index 03c801c42b..7d64055cc3 100644 --- a/editor/plugins/animation_blend_space_1d_editor.cpp +++ b/editor/plugins/animation_blend_space_1d_editor.cpp @@ -37,6 +37,8 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" +#include "scene/gui/check_box.h" +#include "scene/gui/panel_container.h" StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + "blend_position"; @@ -44,6 +46,11 @@ StringName AnimationNodeBlendSpace1DEditor::get_blend_position_path() const { } void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) { @@ -69,11 +76,8 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_animation_tree(); - ERR_FAIL_COND(!gp); - - if (gp->has_node(gp->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); + if (tree->has_node(tree->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); if (ap) { List<StringName> names; @@ -178,7 +182,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); + tree->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -201,13 +205,18 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= blend_space->get_max_space() - blend_space->get_min_space(); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); + tree->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } } void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label")); Color linecolor_soft = linecolor; linecolor_soft.a *= 0.5; @@ -299,7 +308,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_draw() { color.a *= 0.5; } - float point = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(get_blend_position_path()); + float point = tree->get(get_blend_position_path()); point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); point *= s.width; @@ -573,12 +582,17 @@ void AnimationNodeBlendSpace1DEditor::_notification(int p_what) { } break; case NOTIFICATION_PROCESS: { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + String error; - if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { + if (!tree->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); + } else if (tree->is_state_invalid()) { + error = tree->get_invalid_state_reason(); } if (error != error_label->get_text()) { diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp index f27fd0cded..526f69732b 100644 --- a/editor/plugins/animation_blend_space_2d_editor.cpp +++ b/editor/plugins/animation_blend_space_2d_editor.cpp @@ -42,9 +42,12 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" +#include "scene/gui/check_box.h" #include "scene/gui/grid_container.h" #include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" #include "scene/gui/panel.h" +#include "scene/gui/panel_container.h" #include "scene/main/window.h" bool AnimationNodeBlendSpace2DEditor::can_edit(const Ref<AnimationNode> &p_node) { @@ -92,6 +95,11 @@ StringName AnimationNodeBlendSpace2DEditor::get_blend_position_path() const { } void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEvent> &p_event) { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + Ref<InputEventKey> k = p_event; if (tool_select->is_pressed() && k.is_valid() && k->is_pressed() && k->get_keycode() == Key::KEY_DELETE && !k->is_echo()) { if (selected_point != -1 || selected_triangle != -1) { @@ -115,10 +123,8 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_animation_tree(); - ERR_FAIL_COND(!gp); - if (gp && gp->has_node(gp->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); + if (tree->has_node(tree->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); if (ap) { List<StringName> names; ap->get_animation_list(&names); @@ -272,7 +278,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); + tree->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -308,7 +314,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven blend_pos *= (blend_space->get_max_space() - blend_space->get_min_space()); blend_pos += blend_space->get_min_space(); - AnimationTreeEditor::get_singleton()->get_animation_tree()->set(get_blend_position_path(), blend_pos); + tree->set(get_blend_position_path(), blend_pos); blend_space_draw->queue_redraw(); } @@ -435,6 +441,11 @@ void AnimationNodeBlendSpace2DEditor::_tool_switch(int p_tool) { } void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + Color linecolor = get_theme_color(SNAME("font_color"), SNAME("Label")); Color linecolor_soft = linecolor; linecolor_soft.a *= 0.5; @@ -593,7 +604,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_draw() { color.a *= 0.5; } - Vector2 blend_pos = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(get_blend_position_path()); + Vector2 blend_pos = tree->get(get_blend_position_path()); Vector2 point = blend_pos; point = (point - blend_space->get_min_space()) / (blend_space->get_max_space() - blend_space->get_min_space()); @@ -803,14 +814,19 @@ void AnimationNodeBlendSpace2DEditor::_notification(int p_what) { } break; case NOTIFICATION_PROCESS: { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + String error; - if (!AnimationTreeEditor::get_singleton()->get_animation_tree()) { + if (!tree) { error = TTR("BlendSpace2D does not belong to an AnimationTree node."); - } else if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { + } else if (!tree->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); + } else if (tree->is_state_invalid()) { + error = tree->get_invalid_state_reason(); } else if (blend_space->get_triangle_count() == 0) { error = TTR("No triangles exist, so no blending can take place."); } diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp index 9da6e15e75..509caa78ef 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.cpp +++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp @@ -41,9 +41,11 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/animation/animation_player.h" +#include "scene/gui/check_box.h" #include "scene/gui/menu_button.h" #include "scene/gui/panel.h" #include "scene/gui/progress_bar.h" +#include "scene/gui/separator.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" @@ -97,6 +99,9 @@ Size2 AnimationNodeBlendTreeEditor::get_minimum_size() const { void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) { AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } updating = true; Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS); @@ -113,6 +118,11 @@ void AnimationNodeBlendTreeEditor::update_graph() { return; } + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + visible_properties.clear(); graph->set_scroll_ofs(blend_tree->get_graph_offset() * EDSCALE); @@ -175,10 +185,10 @@ void AnimationNodeBlendTreeEditor::update_graph() { continue; } String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name; - EditorProperty *prop = EditorInspector::instantiate_property_editor(AnimationTreeEditor::get_singleton()->get_animation_tree(), F.type, base_path, F.hint, F.hint_string, F.usage); + EditorProperty *prop = EditorInspector::instantiate_property_editor(tree, F.type, base_path, F.hint, F.hint_string, F.usage); if (prop) { prop->set_read_only(read_only); - prop->set_object_and_property(AnimationTreeEditor::get_singleton()->get_animation_tree(), base_path); + prop->set_object_and_property(tree, base_path); prop->update_property(); prop->set_name_split_ratio(0); prop->connect("property_changed", callable_mp(this, &AnimationNodeBlendTreeEditor::_property_changed)); @@ -226,9 +236,8 @@ void AnimationNodeBlendTreeEditor::update_graph() { ProgressBar *pb = memnew(ProgressBar); - AnimationTree *player = AnimationTreeEditor::get_singleton()->get_animation_tree(); - if (player->has_node(player->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(player->get_node(player->get_animation_player())); + if (tree->has_node(tree->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); if (ap) { List<StringName> anims; ap->get_animation_list(&anims); @@ -374,11 +383,11 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) { undo_redo->commit_action(); } -void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position) { +void AnimationNodeBlendTreeEditor::_popup(bool p_has_input_ports, const Vector2 &p_node_position) { _update_options_menu(p_has_input_ports); use_position_from_popup_menu = true; position_from_popup_menu = p_node_position; - add_node->get_popup()->set_position(p_popup_position); + add_node->get_popup()->set_position(graph->get_screen_position() + graph->get_local_mouse_position()); add_node->get_popup()->reset_size(); add_node->get_popup()->popup(); } @@ -388,7 +397,7 @@ void AnimationNodeBlendTreeEditor::_popup_request(const Vector2 &p_position) { return; } - _popup(false, graph->get_screen_position() + graph->get_local_mouse_position(), p_position); + _popup(false, p_position); } void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position) { @@ -399,7 +408,7 @@ void AnimationNodeBlendTreeEditor::_connection_to_empty(const String &p_from, in Ref<AnimationNode> node = blend_tree->get_node(p_from); if (node.is_valid()) { from_node = p_from; - _popup(true, p_release_position, graph->get_global_mouse_position()); + _popup(true, p_release_position); } } @@ -412,7 +421,7 @@ void AnimationNodeBlendTreeEditor::_connection_from_empty(const String &p_to, in if (node.is_valid()) { to_node = p_to; to_slot = p_to_slot; - _popup(false, p_release_position, graph->get_global_mouse_position()); + _popup(false, p_release_position); } } @@ -599,14 +608,19 @@ bool AnimationNodeBlendTreeEditor::_update_filters(const Ref<AnimationNode> &ano return false; } - NodePath player_path = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_animation_player(); + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return false; + } + + NodePath player_path = tree->get_animation_player(); - if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->has_node(player_path)) { + if (!tree->has_node(player_path)) { EditorNode::get_singleton()->show_warning(TTR("No animation player set, so unable to retrieve track names.")); return false; } - AnimationPlayer *player = Object::cast_to<AnimationPlayer>(AnimationTreeEditor::get_singleton()->get_animation_tree()->get_node(player_path)); + AnimationPlayer *player = Object::cast_to<AnimationPlayer>(tree->get_node(player_path)); if (!player) { EditorNode::get_singleton()->show_warning(TTR("Player path set is invalid, so unable to retrieve track names.")); return false; @@ -837,12 +851,17 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { } break; case NOTIFICATION_PROCESS: { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; // Node has been changed. + } + String error; - if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { + if (!tree->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); + } else if (tree->is_state_invalid()) { + error = tree->get_invalid_state_reason(); } if (error != error_label->get_text()) { @@ -859,16 +878,15 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { for (const AnimationNodeBlendTree::NodeConnection &E : conns) { float activity = 0; StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; - if (AnimationTreeEditor::get_singleton()->get_animation_tree() && !AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { - activity = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_connection_activity(path, E.input_index); + if (!tree->is_state_invalid()) { + activity = tree->get_connection_activity(path, E.input_index); } graph->set_connection_activity(E.output_node, 0, E.input_node, E.input_index, activity); } - AnimationTree *graph_player = AnimationTreeEditor::get_singleton()->get_animation_tree(); AnimationPlayer *player = nullptr; - if (graph_player->has_node(graph_player->get_animation_player())) { - player = Object::cast_to<AnimationPlayer>(graph_player->get_node(graph_player->get_animation_player())); + if (tree->has_node(tree->get_animation_player())) { + player = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); } if (player) { @@ -881,7 +899,7 @@ void AnimationNodeBlendTreeEditor::_notification(int p_what) { E.value->set_max(anim->get_length()); //StringName path = AnimationTreeEditor::get_singleton()->get_base_path() + E.input_node; StringName time_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E.key) + "/time"; - E.value->set_value(AnimationTreeEditor::get_singleton()->get_animation_tree()->get(time_path)); + E.value->set_value(tree->get(time_path)); } } } @@ -935,6 +953,11 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima return; } + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + String prev_name = blend_tree->get_node_name(p_node); ERR_FAIL_COND(prev_name.is_empty()); GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(prev_name)); @@ -963,8 +986,8 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima undo_redo->create_action(TTR("Node Renamed")); undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name); undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name); - undo_redo->add_do_method(AnimationTreeEditor::get_singleton()->get_animation_tree(), "rename_parameter", base_path + prev_name, base_path + name); - undo_redo->add_undo_method(AnimationTreeEditor::get_singleton()->get_animation_tree(), "rename_parameter", base_path + name, base_path + prev_name); + undo_redo->add_do_method(tree, "rename_parameter", base_path + prev_name, base_path + name); + undo_redo->add_undo_method(tree, "rename_parameter", base_path + name, base_path + prev_name); undo_redo->add_do_method(this, "update_graph"); undo_redo->add_undo_method(this, "update_graph"); undo_redo->commit_action(); diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index fb19cce147..4b55aa9b3f 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -117,7 +117,7 @@ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { void _filter_toggled(); Ref<AnimationNode> _filter_edit; - void _popup(bool p_has_input_ports, const Vector2 &p_popup_position, const Vector2 &p_node_position); + void _popup(bool p_has_input_ports, const Vector2 &p_node_position); void _popup_request(const Vector2 &p_position); void _connection_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_position); void _connection_from_empty(const String &p_to, int p_to_slot, const Vector2 &p_release_position); diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index e377366c0d..10b5271fc8 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -32,6 +32,7 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" void AnimationLibraryEditor::set_animation_player(Object *p_player) { diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index 85739d0d8f..5183a738ae 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -40,9 +40,11 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/canvas_item_editor_plugin.h" // For onion skinning. #include "editor/plugins/node_3d_editor_plugin.h" // For onion skinning. #include "editor/scene_tree_dock.h" +#include "scene/gui/separator.h" #include "scene/main/window.h" #include "scene/resources/animation.h" #include "scene/scene_string_names.h" @@ -197,6 +199,7 @@ void AnimationPlayerEditor::_play_pressed() { if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself } + ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); player->play(current); } @@ -209,13 +212,12 @@ void AnimationPlayerEditor::_play_from_pressed() { if (!current.is_empty()) { float time = player->get_current_animation_position(); - if (current == player->get_assigned_animation() && player->is_playing()) { player->stop(); //so it won't blend with itself } - - player->play(current); + ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); player->seek(time); + player->play(current); } //unstop @@ -235,6 +237,7 @@ void AnimationPlayerEditor::_play_bw_pressed() { if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself } + ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); player->play(current, -1, -1, true); } @@ -250,9 +253,9 @@ void AnimationPlayerEditor::_play_bw_from_pressed() { if (current == player->get_assigned_animation()) { player->stop(); //so it won't blend with itself } - - player->play(current, -1, -1, true); + ERR_FAIL_COND_EDMSG(!_validate_tracks(player->get_animation(current)), "Animation tracks may have any invalid key, abort playing."); player->seek(time); + player->play(current, -1, -1, true); } //unstop @@ -1562,6 +1565,53 @@ void AnimationPlayerEditor::_pin_pressed() { SceneTreeDock::get_singleton()->get_tree_editor()->update_tree(); } +bool AnimationPlayerEditor::_validate_tracks(const Ref<Animation> p_anim) { + bool is_valid = true; + if (!p_anim.is_valid()) { + return true; // There is a problem outside of the animation track. + } + int len = p_anim->get_track_count(); + for (int i = 0; i < len; i++) { + Animation::TrackType ttype = p_anim->track_get_type(i); + if (ttype == Animation::TYPE_ROTATION_3D) { + int key_len = p_anim->track_get_key_count(i); + for (int j = 0; j < key_len; j++) { + Quaternion q; + p_anim->rotation_track_get_key(i, j, &q); + ERR_BREAK_EDMSG(!q.is_normalized(), "AnimationPlayer: '" + player->get_name() + "', Animation: '" + player->get_current_animation() + "', rotation track: '" + p_anim->track_get_path(i) + "' contains unnormalized Quaternion key."); + } + } else if (ttype == Animation::TYPE_VALUE) { + int key_len = p_anim->track_get_key_count(i); + if (key_len == 0) { + continue; + } + switch (p_anim->track_get_key_value(i, 0).get_type()) { + case Variant::QUATERNION: { + for (int j = 0; j < key_len; j++) { + Quaternion q = Quaternion(p_anim->track_get_key_value(i, j)); + if (!q.is_normalized()) { + is_valid = false; + ERR_BREAK_EDMSG(true, "AnimationPlayer: '" + player->get_name() + "', Animation: '" + player->get_current_animation() + "', value track: '" + p_anim->track_get_path(i) + "' contains unnormalized Quaternion key."); + } + } + } break; + case Variant::TRANSFORM3D: { + for (int j = 0; j < key_len; j++) { + Transform3D t = Transform3D(p_anim->track_get_key_value(i, j)); + if (!t.basis.orthonormalized().is_rotation()) { + is_valid = false; + ERR_BREAK_EDMSG(true, "AnimationPlayer: '" + player->get_name() + "', Animation: '" + player->get_current_animation() + "', value track: '" + p_anim->track_get_path(i) + "' contains corrupted basis (some axes are too close other axis or scaled by zero) Transform3D key."); + } + } + } break; + default: { + } break; + } + } + } + return is_valid; +} + void AnimationPlayerEditor::_bind_methods() { ClassDB::bind_method(D_METHOD("_animation_new"), &AnimationPlayerEditor::_animation_new); ClassDB::bind_method(D_METHOD("_animation_rename"), &AnimationPlayerEditor::_animation_rename); diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 6370b00ea8..53d460fc9e 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -212,6 +212,8 @@ class AnimationPlayerEditor : public VBoxContainer { void _start_onion_skinning(); void _stop_onion_skinning(); + bool _validate_tracks(const Ref<Animation> p_anim); + void _pin_pressed(); String _get_current() const; diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp index bd34d3808d..66a0c746d9 100644 --- a/editor/plugins/animation_state_machine_editor.cpp +++ b/editor/plugins/animation_state_machine_editor.cpp @@ -43,7 +43,10 @@ #include "scene/animation/animation_blend_tree.h" #include "scene/animation/animation_player.h" #include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" #include "scene/gui/panel.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/main/viewport.h" #include "scene/main/window.h" @@ -76,7 +79,12 @@ void AnimationNodeStateMachineEditor::edit(const Ref<AnimationNode> &p_node) { } void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEvent> &p_event) { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + + Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (playback.is_null()) { return; } @@ -733,6 +741,11 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() { } void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + menu->clear(); animations_menu->clear(); animations_to_add.clear(); @@ -742,10 +755,8 @@ void AnimationNodeStateMachineEditor::_open_menu(const Vector2 &p_position) { ClassDB::get_inheriters_from_class("AnimationRootNode", &classes); menu->add_submenu_item(TTR("Add Animation"), "animations"); - AnimationTree *gp = AnimationTreeEditor::get_singleton()->get_animation_tree(); - ERR_FAIL_COND(!gp); - if (gp && gp->has_node(gp->get_animation_player())) { - AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(gp->get_node(gp->get_animation_player())); + if (tree->has_node(tree->get_animation_player())) { + AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(tree->get_node(tree->get_animation_player())); if (ap) { List<StringName> names; ap->get_animation_list(&names); @@ -1189,7 +1200,12 @@ void AnimationNodeStateMachineEditor::_clip_dst_line_to_rect(const Vector2 &p_fr } void AnimationNodeStateMachineEditor::_state_machine_draw() { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + + Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); Ref<StyleBoxFlat> style = get_theme_stylebox(SNAME("state_machine_frame"), SNAME("GraphNode")); Ref<StyleBoxFlat> style_selected = get_theme_stylebox(SNAME("state_machine_selected_frame"), SNAME("GraphNode")); @@ -1377,7 +1393,7 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } StringName fullpath = AnimationTreeEditor::get_singleton()->get_base_path() + String(tl.advance_condition_name); - if (tl.advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_animation_tree()->get(fullpath))) { + if (tl.advance_condition_name != StringName() && bool(tree->get(fullpath))) { tl.advance_condition_state = true; tl.auto_advance = true; } @@ -1492,7 +1508,12 @@ void AnimationNodeStateMachineEditor::_state_machine_draw() { } void AnimationNodeStateMachineEditor::_state_machine_pos_draw() { - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + + Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (!playback.is_valid() || !playback->is_playing()) { return; @@ -1584,17 +1605,22 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { } break; case NOTIFICATION_PROCESS: { + AnimationTree *tree = AnimationTreeEditor::get_singleton()->get_animation_tree(); + if (!tree) { + return; + } + String error; - Ref<AnimationNodeStateMachinePlayback> playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); + Ref<AnimationNodeStateMachinePlayback> playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + "playback"); if (error_time > 0) { error = error_text; error_time -= get_process_delta_time(); - } else if (!AnimationTreeEditor::get_singleton()->get_animation_tree()->is_active()) { + } else if (!tree->is_active()) { error = TTR("AnimationTree is inactive.\nActivate to enable playback, check node warnings if activation fails."); - } else if (AnimationTreeEditor::get_singleton()->get_animation_tree()->is_state_invalid()) { - error = AnimationTreeEditor::get_singleton()->get_animation_tree()->get_invalid_state_reason(); + } else if (tree->is_state_invalid()) { + error = tree->get_invalid_state_reason(); /*} else if (state_machine->get_parent().is_valid() && state_machine->get_parent()->is_class("AnimationNodeStateMachine")) { if (state_machine->get_start_node() == StringName() || state_machine->get_end_node() == StringName()) { error = TTR("Start and end nodes are needed for a sub-transition."); @@ -1646,7 +1672,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { break; } - bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name))); + bool acstate = transition_lines[i].advance_condition_name != StringName() && bool(tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + String(transition_lines[i].advance_condition_name))); if (transition_lines[i].advance_condition_state != acstate) { state_machine_draw->queue_redraw(); @@ -1701,7 +1727,7 @@ void AnimationNodeStateMachineEditor::_notification(int p_what) { Ref<AnimationNodeStateMachinePlayback> current_node_playback; while (anodesm.is_valid()) { - current_node_playback = AnimationTreeEditor::get_singleton()->get_animation_tree()->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback"); + current_node_playback = tree->get(AnimationTreeEditor::get_singleton()->get_base_path() + next + "/playback"); next += "/" + current_node_playback->get_current_node(); anodesm = anodesm->get_node(current_node_playback->get_current_node()); } diff --git a/editor/plugins/animation_tree_editor_plugin.cpp b/editor/plugins/animation_tree_editor_plugin.cpp index 61aa861a3f..c31a2689ec 100644 --- a/editor/plugins/animation_tree_editor_plugin.cpp +++ b/editor/plugins/animation_tree_editor_plugin.cpp @@ -77,6 +77,7 @@ void AnimationTreeEditor::edit(AnimationTree *p_tree) { void AnimationTreeEditor::_node_removed(Node *p_node) { if (p_node == tree) { tree = nullptr; + _clear_editors(); } } @@ -151,7 +152,6 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { } else { current_root = ObjectID(); edited_path = button_path; - for (int i = 0; i < editors.size(); i++) { editors[i]->edit(Ref<AnimationNode>()); editors[i]->hide(); @@ -161,6 +161,17 @@ void AnimationTreeEditor::edit_path(const Vector<String> &p_path) { _update_path(); } +void AnimationTreeEditor::_clear_editors() { + button_path.clear(); + current_root = ObjectID(); + edited_path = button_path; + for (int i = 0; i < editors.size(); i++) { + editors[i]->edit(Ref<AnimationNode>()); + editors[i]->hide(); + } + _update_path(); +} + Vector<String> AnimationTreeEditor::get_edited_path() const { return button_path; } diff --git a/editor/plugins/animation_tree_editor_plugin.h b/editor/plugins/animation_tree_editor_plugin.h index e1d9536f03..b933523057 100644 --- a/editor/plugins/animation_tree_editor_plugin.h +++ b/editor/plugins/animation_tree_editor_plugin.h @@ -60,6 +60,7 @@ class AnimationTreeEditor : public VBoxContainer { Vector<AnimationTreeNodeEditorPlugin *> editors; void _update_path(); + void _clear_editors(); ObjectID current_root; void _path_button_pressed(int p_path); diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 72bee901bf..7c3ecd5d4e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/project_settings_editor.h" +#include "scene/gui/menu_button.h" static inline void setup_http_request(HTTPRequest *request) { request->set_use_threads(EDITOR_DEF("asset_library/use_threads", true)); diff --git a/editor/plugins/bit_map_editor_plugin.cpp b/editor/plugins/bit_map_editor_plugin.cpp index 657c5a36b6..8d9b3147a9 100644 --- a/editor/plugins/bit_map_editor_plugin.cpp +++ b/editor/plugins/bit_map_editor_plugin.cpp @@ -31,6 +31,8 @@ #include "bit_map_editor_plugin.h" #include "editor/editor_scale.h" +#include "scene/gui/label.h" +#include "scene/gui/texture_rect.h" void BitMapEditor::setup(const Ref<BitMap> &p_bitmap) { texture_rect->set_texture(ImageTexture::create_from_image(p_bitmap->convert_to_image())); diff --git a/editor/plugins/bone_map_editor_plugin.cpp b/editor/plugins/bone_map_editor_plugin.cpp index 9ceedb18b3..4bf11f0627 100644 --- a/editor/plugins/bone_map_editor_plugin.cpp +++ b/editor/plugins/bone_map_editor_plugin.cpp @@ -31,10 +31,14 @@ #include "bone_map_editor_plugin.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/import/post_import_plugin_skeleton_renamer.h" #include "editor/import/post_import_plugin_skeleton_rest_fixer.h" #include "editor/import/post_import_plugin_skeleton_track_organizer.h" #include "editor/import/scene_import_settings.h" +#include "scene/gui/aspect_ratio_container.h" +#include "scene/gui/separator.h" +#include "scene/gui/texture_rect.h" void BoneMapperButton::fetch_textures() { if (selected) { diff --git a/editor/plugins/bone_map_editor_plugin.h b/editor/plugins/bone_map_editor_plugin.h index 16e5403978..e6a35d1120 100644 --- a/editor/plugins/bone_map_editor_plugin.h +++ b/editor/plugins/bone_map_editor_plugin.h @@ -41,11 +41,14 @@ #endif #include "scene/3d/skeleton_3d.h" +#include "scene/gui/box_container.h" #include "scene/gui/color_rect.h" #include "scene/gui/dialogs.h" #include "scene/resources/bone_map.h" #include "scene/resources/texture.h" +class AspectRatioContainer; + class BoneMapperButton : public TextureButton { GDCLASS(BoneMapperButton, TextureButton); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 0fe77ec400..aab64587ce 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -32,15 +32,14 @@ #include "core/config/project_settings.h" #include "core/input/input.h" -#include "core/math/geometry_2d.h" #include "core/os/keyboard.h" -#include "core/string/print_string.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_toaster.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/editor_zoom_widget.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" @@ -55,6 +54,7 @@ #include "scene/gui/grid_container.h" #include "scene/gui/nine_patch_rect.h" #include "scene/gui/separator.h" +#include "scene/gui/split_container.h" #include "scene/gui/subviewport_container.h" #include "scene/gui/view_panner.h" #include "scene/main/canvas_layer.h" @@ -5504,6 +5504,11 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons Ref<Texture2D> texture = Ref<Texture2D>(Object::cast_to<Texture2D>(*res)); Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res)); if (texture != nullptr || scene != nullptr) { + bool root_node_selected = EditorNode::get_singleton()->get_editor_selection()->is_selected(EditorNode::get_singleton()->get_edited_scene()); + String desc = TTR("Drag and drop to add as child of current scene's root node.") + "\n" + TTR("Hold Ctrl when dropping to add as child of selected node."); + if (!root_node_selected) { + desc += "\n" + TTR("Hold Shift when dropping to add as sibling of selected node."); + } if (texture != nullptr) { Sprite2D *sprite = memnew(Sprite2D); sprite->set_texture(texture); @@ -5511,14 +5516,15 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons preview_node->add_child(sprite); label->show(); label_desc->show(); - label_desc->set_text(TTR("Drag and drop to add as child of current scene's root node.\nHold Ctrl when dropping to add as child of selected node.\nHold Shift when dropping to add as sibling of selected node.\nHold Alt when dropping to add as a different node type.")); + desc += "\n" + TTR("Hold Alt when dropping to add as a different node type."); + label_desc->set_text(desc); } else { if (scene.is_valid()) { Node *instance = scene->instantiate(); if (instance) { preview_node->add_child(instance); label_desc->show(); - label_desc->set_text(TTR("Drag and drop to add as child of current scene's root node.\nHold Ctrl when dropping to add as child of selected node.\nHold Shift when dropping to add as sibling of selected node.")); + label_desc->set_text(desc); } } } @@ -5596,7 +5602,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & // make visible for certain node type if (Object::cast_to<Control>(child)) { Size2 texture_size = texture->get_size(); - undo_redo->add_do_property(child, "rect_size", texture_size); + undo_redo->add_do_property(child, "size", texture_size); } else if (Object::cast_to<Polygon2D>(child)) { Size2 texture_size = texture->get_size(); Vector<Vector2> list = { @@ -5612,6 +5618,11 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String & Transform2D xform = canvas_item_editor->get_canvas_transform(); Point2 target_position = xform.affine_inverse().xform(p_point); + // Adjust position for Control and TouchScreenButton + if (Object::cast_to<Control>(child) || Object::cast_to<TouchScreenButton>(child)) { + target_position -= texture->get_size() / 2; + } + // there's nothing to be used as source position so snapping will work as absolute if enabled target_position = canvas_item_editor->snap_point(target_position); undo_redo->add_do_method(child, "set_global_position", target_position); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index cc98aa8c51..9c7d0fbe6f 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -32,22 +32,21 @@ #define CANVAS_ITEM_EDITOR_PLUGIN_H #include "editor/editor_plugin.h" -#include "editor/editor_zoom_widget.h" +#include "scene/gui/base_button.h" #include "scene/gui/box_container.h" -#include "scene/gui/check_box.h" -#include "scene/gui/label.h" -#include "scene/gui/panel_container.h" -#include "scene/gui/spin_box.h" -#include "scene/gui/split_container.h" -#include "scene/gui/texture_rect.h" -#include "scene/main/canvas_item.h" class AcceptDialog; +class CanvasItemEditorViewport; class ConfirmationDialog; class EditorData; -class CanvasItemEditorViewport; +class EditorZoomWidget; +class HScrollBar; +class HSplitContainer; class MenuButton; +class PanelContainer; class ViewPanner; +class VScrollBar; +class VSplitContainer; class CanvasItemEditorSelectedItem : public Object { GDCLASS(CanvasItemEditorSelectedItem, Object); diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 891a22cc71..36b51e0e0c 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -35,7 +35,11 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "scene/2d/cpu_particles_2d.h" +#include "scene/gui/check_box.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" #include "scene/gui/separator.h" +#include "scene/gui/spin_box.h" #include "scene/resources/particle_process_material.h" void CPUParticles2DEditorPlugin::edit(Object *p_object) { diff --git a/editor/plugins/debugger_editor_plugin.cpp b/editor/plugins/debugger_editor_plugin.cpp index dd6187c264..7d04880fb7 100644 --- a/editor/plugins/debugger_editor_plugin.cpp +++ b/editor/plugins/debugger_editor_plugin.cpp @@ -47,7 +47,6 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) { ED_SHORTCUT("debugger/step_over", TTR("Step Over"), Key::F10); ED_SHORTCUT("debugger/break", TTR("Break")); ED_SHORTCUT("debugger/continue", TTR("Continue"), Key::F12); - ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open")); ED_SHORTCUT("debugger/debug_with_external_editor", TTR("Debug with External Editor")); // File Server for deploy with remote filesystem. @@ -85,6 +84,9 @@ DebuggerEditorPlugin::DebuggerEditorPlugin(PopupMenu *p_debug_menu) { debug_menu->add_check_shortcut(ED_SHORTCUT("editor/sync_script_changes", TTR("Synchronize Script Changes")), RUN_RELOAD_SCRIPTS); debug_menu->set_item_tooltip(-1, TTR("When this option is enabled, any script that is saved will be reloaded in the running project.\nWhen used remotely on a device, this is more efficient when the network filesystem option is enabled.")); + debug_menu->add_check_shortcut(ED_SHORTCUT("editor/keep_server_open", TTR("Keep Debug Server Open")), SERVER_KEEP_OPEN); + debug_menu->set_item_tooltip(-1, + TTR("When this option is enabled, the editor debug server will stay open and listen for new sessions started outside of the editor itself.")); // Multi-instance, start/stop instances_menu = memnew(PopupMenu); @@ -176,6 +178,14 @@ void DebuggerEditorPlugin::_menu_option(int p_option) { EditorSettings::get_singleton()->set_project_metadata("debug_options", "run_reload_scripts", !ischecked); } break; + case SERVER_KEEP_OPEN: { + bool ischecked = debug_menu->is_item_checked(debug_menu->get_item_index(SERVER_KEEP_OPEN)); + debug_menu->set_item_checked(debug_menu->get_item_index(SERVER_KEEP_OPEN), !ischecked); + + EditorDebuggerNode::get_singleton()->set_keep_open(!ischecked); + EditorSettings::get_singleton()->set_project_metadata("debug_options", "server_keep_open", !ischecked); + + } break; } } @@ -195,6 +205,7 @@ void DebuggerEditorPlugin::_update_debug_options() { bool check_debug_navigation = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_navigation", false); bool check_live_debug = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_live_debug", true); bool check_reload_scripts = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_reload_scripts", true); + bool check_server_keep_open = EditorSettings::get_singleton()->get_project_metadata("debug_options", "server_keep_open", false); int instances = EditorSettings::get_singleton()->get_project_metadata("debug_options", "run_debug_instances", 1); if (check_deploy_remote) { @@ -218,6 +229,9 @@ void DebuggerEditorPlugin::_update_debug_options() { if (check_reload_scripts) { _menu_option(RUN_RELOAD_SCRIPTS); } + if (check_server_keep_open) { + _menu_option(SERVER_KEEP_OPEN); + } int len = instances_menu->get_item_count(); for (int idx = 0; idx < len; idx++) { diff --git a/editor/plugins/debugger_editor_plugin.h b/editor/plugins/debugger_editor_plugin.h index c706acdb5c..5f682ed5e0 100644 --- a/editor/plugins/debugger_editor_plugin.h +++ b/editor/plugins/debugger_editor_plugin.h @@ -53,6 +53,7 @@ private: RUN_DEBUG_NAVIGATION, RUN_DEPLOY_REMOTE_DEBUG, RUN_RELOAD_SCRIPTS, + SERVER_KEEP_OPEN, }; void _update_debug_options(); diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp index 33992314b0..4370d013be 100644 --- a/editor/plugins/font_config_plugin.cpp +++ b/editor/plugins/font_config_plugin.cpp @@ -31,6 +31,7 @@ #include "font_config_plugin.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/import/dynamic_font_import_settings.h" /*************************************************************************/ diff --git a/editor/plugins/gdextension_export_plugin.h b/editor/plugins/gdextension_export_plugin.h index c5f7d2a047..41edf9ac75 100644 --- a/editor/plugins/gdextension_export_plugin.h +++ b/editor/plugins/gdextension_export_plugin.h @@ -40,7 +40,7 @@ protected: }; void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) { - if (p_type != "NativeExtension") { + if (p_type != "GDExtension") { return; } @@ -54,60 +54,38 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p String entry_symbol = config->get_value("configuration", "entry_symbol"); - List<String> libraries; - - config->get_section_keys("libraries", &libraries); - - bool could_export = false; - for (const String &E : libraries) { - Vector<String> tags = E.split("."); - bool all_tags_met = true; - for (int i = 0; i < tags.size(); i++) { - String tag = tags[i].strip_edges(); - if (!p_features.has(tag)) { - all_tags_met = false; - break; - } - } - - if (all_tags_met) { - String library_path = config->get_value("libraries", E); - if (!library_path.begins_with("res://")) { - print_line("Skipping export of out-of-project library " + library_path); - continue; - } - add_shared_object(library_path, tags); - - if (p_features.has("iOS") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) { - String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n" - "extern void add_ios_init_callback(void (*cb)());\n" - "\n" - "extern \"C\" void $ENTRY();\n" - "void $ENTRY_init() {\n" - " if (&$ENTRY) register_dynamic_symbol((char *)\"$ENTRY\", (void *)$ENTRY);\n" - "}\n" - "struct $ENTRY_struct {\n" - " $ENTRY_struct() {\n" - " add_ios_init_callback($ENTRY_init);\n" - " }\n" - "};\n" - "$ENTRY_struct $ENTRY_struct_instance;\n\n"; - additional_code = additional_code.replace("$ENTRY", entry_symbol); - add_ios_cpp_code(additional_code); - - String linker_flags = "-Wl,-U,_" + entry_symbol; - add_ios_linker_flags(linker_flags); - } - could_export = true; - break; + PackedStringArray tags; + String library_path = GDExtension::find_extension_library( + p_path, config, [p_features](String p_feature) { return p_features.has(p_feature); }, &tags); + if (!library_path.is_empty()) { + add_shared_object(library_path, tags); + + if (p_features.has("iOS") && (library_path.ends_with(".a") || library_path.ends_with(".xcframework"))) { + String additional_code = "extern void register_dynamic_symbol(char *name, void *address);\n" + "extern void add_ios_init_callback(void (*cb)());\n" + "\n" + "extern \"C\" void $ENTRY();\n" + "void $ENTRY_init() {\n" + " if (&$ENTRY) register_dynamic_symbol((char *)\"$ENTRY\", (void *)$ENTRY);\n" + "}\n" + "struct $ENTRY_struct {\n" + " $ENTRY_struct() {\n" + " add_ios_init_callback($ENTRY_init);\n" + " }\n" + "};\n" + "$ENTRY_struct $ENTRY_struct_instance;\n\n"; + additional_code = additional_code.replace("$ENTRY", entry_symbol); + add_ios_cpp_code(additional_code); + + String linker_flags = "-Wl,-U,_" + entry_symbol; + add_ios_linker_flags(linker_flags); } - } - if (!could_export) { - Vector<String> tags; + } else { + Vector<String> features_vector; for (const String &E : p_features) { - tags.append(E); + features_vector.append(E); } - ERR_FAIL_MSG(vformat("No suitable library found. The libraries' tags referred to an invalid feature flag. Possible feature flags for your platform: %s", p_path, String(", ").join(tags))); + ERR_FAIL_MSG(vformat("No suitable library found for GDExtension: %s. Possible feature flags for your platform: %s", p_path, String(", ").join(features_vector))); } List<String> dependencies; @@ -115,11 +93,11 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p config->get_section_keys("dependencies", &dependencies); } - for (const String &E : libraries) { - Vector<String> tags = E.split("."); + for (const String &E : dependencies) { + Vector<String> dependency_tags = E.split("."); bool all_tags_met = true; - for (int i = 0; i < tags.size(); i++) { - String tag = tags[i].strip_edges(); + for (int i = 0; i < dependency_tags.size(); i++) { + String tag = dependency_tags[i].strip_edges(); if (!p_features.has(tag)) { all_tags_met = false; break; @@ -129,13 +107,12 @@ void GDExtensionExportPlugin::_export_file(const String &p_path, const String &p if (all_tags_met) { Dictionary dependency = config->get_value("dependencies", E); for (const Variant *key = dependency.next(nullptr); key; key = dependency.next(key)) { - String library_path = *key; + String dependency_path = *key; String target_path = dependency[*key]; - if (!library_path.begins_with("res://")) { - print_line("Skipping export of out-of-project library " + library_path); - continue; + if (dependency_path.is_relative_path()) { + dependency_path = p_path.get_base_dir().path_join(dependency_path); } - add_shared_object(library_path, tags, target_path); + add_shared_object(dependency_path, dependency_tags, target_path); } break; } diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp index 87381b3221..0fa3efba9a 100644 --- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/scene_tree_dock.h" #include "scene/2d/cpu_particles_2d.h" +#include "scene/gui/menu_button.h" #include "scene/gui/separator.h" #include "scene/resources/particle_process_material.h" diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp index db3a46d1f1..b2878244d0 100644 --- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp +++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp @@ -36,6 +36,8 @@ #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/cpu_particles_3d.h" +#include "scene/3d/mesh_instance_3d.h" +#include "scene/gui/menu_button.h" #include "scene/resources/particle_process_material.h" bool GPUParticles3DEditorBase::_generate(Vector<Vector3> &points, Vector<Vector3> &normals) { diff --git a/editor/plugins/material_editor_plugin.h b/editor/plugins/material_editor_plugin.h index 076fd5e537..7d7d41785b 100644 --- a/editor/plugins/material_editor_plugin.h +++ b/editor/plugins/material_editor_plugin.h @@ -41,7 +41,9 @@ #include "scene/resources/material.h" #include "scene/resources/primitive_meshes.h" +class SubViewport; class SubViewportContainer; +class TextureButton; class MaterialEditor : public Control { GDCLASS(MaterialEditor, Control); diff --git a/editor/plugins/mesh_editor_plugin.cpp b/editor/plugins/mesh_editor_plugin.cpp index 57dc92a9ee..79fbf19f89 100644 --- a/editor/plugins/mesh_editor_plugin.cpp +++ b/editor/plugins/mesh_editor_plugin.cpp @@ -32,6 +32,8 @@ #include "core/config/project_settings.h" #include "editor/editor_scale.h" +#include "scene/gui/texture_button.h" +#include "scene/main/viewport.h" void MeshEditor::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); diff --git a/editor/plugins/mesh_editor_plugin.h b/editor/plugins/mesh_editor_plugin.h index b8d6562c5c..8eecc909b6 100644 --- a/editor/plugins/mesh_editor_plugin.h +++ b/editor/plugins/mesh_editor_plugin.h @@ -40,6 +40,9 @@ #include "scene/resources/camera_attributes.h" #include "scene/resources/material.h" +class SubViewport; +class TextureButton; + class MeshEditor : public SubViewportContainer { GDCLASS(MeshEditor, SubViewportContainer); diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp index 68fbce771a..aec43290f9 100644 --- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp +++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp @@ -38,6 +38,10 @@ #include "scene/3d/navigation_region_3d.h" #include "scene/3d/physics_body_3d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/resources/concave_polygon_shape_3d.h" +#include "scene/resources/convex_polygon_shape_3d.h" +#include "scene/scene_string_names.h" void MeshInstance3DEditor::_node_removed(Node *p_node) { if (p_node == node) { @@ -66,7 +70,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { List<Node *> selection = editor_selection->get_selected_node_list(); if (selection.is_empty()) { - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); if (shape.is_null()) { err_dialog->set_text(TTR("Couldn't create a Trimesh collision shape.")); err_dialog->popup_centered(); @@ -84,8 +88,8 @@ void MeshInstance3DEditor::_menu_option(int p_option) { 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_method(Node3DEditor::get_singleton(), "_request_gizmo", body); - ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, body); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, cshape); ur->add_do_reference(body); ur->add_undo_method(node, "remove_child", body); ur->commit_action(); @@ -105,7 +109,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { continue; } - Ref<Shape3D> shape = m->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = m->create_trimesh_shape(); if (shape.is_null()) { continue; } @@ -120,8 +124,8 @@ void MeshInstance3DEditor::_menu_option(int p_option) { 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_method(Node3DEditor::get_singleton(), "_request_gizmo", body); - ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, body); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, cshape); ur->add_do_reference(body); ur->add_undo_method(instance, "remove_child", body); } @@ -137,7 +141,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { return; } - Ref<Shape3D> shape = mesh->create_trimesh_shape(); + Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape(); if (shape.is_null()) { return; } @@ -155,7 +159,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { 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_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, cshape); ur->add_do_reference(cshape); ur->add_undo_method(node->get_parent(), "remove_child", cshape); ur->commit_action(); @@ -171,7 +175,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { bool simplify = (p_option == MENU_OPTION_CREATE_SIMPLIFIED_CONVEX_COLLISION_SHAPE); - Ref<Shape3D> shape = mesh->create_convex_shape(true, simplify); + Ref<ConvexPolygonShape3D> shape = mesh->create_convex_shape(true, simplify); if (shape.is_null()) { err_dialog->set_text(TTR("Couldn't create a single convex collision shape.")); @@ -195,7 +199,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { 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_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, cshape); ur->add_do_reference(cshape); ur->add_undo_method(node->get_parent(), "remove_child", cshape); @@ -234,7 +238,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->add_do_method(node->get_parent(), "add_child", cshape); 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_method(Node3DEditor::get_singleton(), "_request_gizmo", cshape); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, cshape); ur->add_do_reference(cshape); ur->add_undo_method(node->get_parent(), "remove_child", cshape); } @@ -260,7 +264,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) { ur->add_do_method(node, "add_child", nmi, true); ur->add_do_method(nmi, "set_owner", owner); - ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", nmi); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, nmi); ur->add_do_reference(nmi); ur->add_undo_method(node, "remove_child", nmi); @@ -495,7 +499,7 @@ void MeshInstance3DEditor::_create_outline_mesh() { ur->add_do_method(node, "add_child", mi, true); ur->add_do_method(mi, "set_owner", owner); - ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", mi); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, mi); ur->add_do_reference(mi); ur->add_undo_method(node, "remove_child", mi); diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp index 6654b03a0d..4a8e5d9979 100644 --- a/editor/plugins/mesh_library_editor_plugin.cpp +++ b/editor/plugins/mesh_library_editor_plugin.cpp @@ -33,11 +33,13 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "editor/inspector_dock.h" #include "main/main.h" #include "node_3d_editor_plugin.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/navigation_region_3d.h" #include "scene/3d/physics_body_3d.h" +#include "scene/gui/menu_button.h" #include "scene/main/window.h" #include "scene/resources/packed_scene.h" diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index b0e206b020..40fac060cd 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -35,6 +35,8 @@ #include "node_3d_editor_plugin.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" void MultiMeshEditor::_node_removed(Node *p_node) { if (p_node == node) { diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp index 0af2a13df2..c8b80db334 100644 --- a/editor/plugins/node_3d_editor_gizmos.cpp +++ b/editor/plugins/node_3d_editor_gizmos.cpp @@ -30,6 +30,7 @@ #include "node_3d_editor_gizmos.h" +#include "core/config/project_settings.h" #include "core/math/convex_hull.h" #include "core/math/geometry_2d.h" #include "core/math/geometry_3d.h" @@ -1732,6 +1733,24 @@ Camera3DGizmoPlugin::Camera3DGizmoPlugin() { create_handle_material("handles"); } +Size2i Camera3DGizmoPlugin::_get_viewport_size(Camera3D *p_camera) { + Viewport *viewport = p_camera->get_viewport(); + + Window *window = Object::cast_to<Window>(viewport); + if (window) { + return window->get_size(); + } + + SubViewport *sub_viewport = Object::cast_to<SubViewport>(viewport); + ERR_FAIL_NULL_V(sub_viewport, Size2i()); + + if (sub_viewport == EditorNode::get_singleton()->get_scene_root()) { + return Size2(GLOBAL_GET("display/window/size/viewport_width"), GLOBAL_GET("display/window/size/viewport_height")); + } + + return sub_viewport->get_size(); +} + bool Camera3DGizmoPlugin::has_gizmo(Node3D *p_spatial) { return Object::cast_to<Camera3D>(p_spatial) != nullptr; } @@ -1830,6 +1849,10 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { Ref<Material> material = get_material("camera_material", p_gizmo); + const Size2i viewport_size = _get_viewport_size(camera); + const real_t viewport_aspect = viewport_size.x > 0 && viewport_size.y > 0 ? viewport_size.aspect() : 1.0; + const Size2 size_factor = viewport_aspect > 1.0 ? Size2(1.0, 1.0 / viewport_aspect) : Size2(viewport_aspect, 1.0); + #define ADD_TRIANGLE(m_a, m_b, m_c) \ { \ lines.push_back(m_a); \ @@ -1857,10 +1880,11 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { // The real FOV is halved for accurate representation float fov = camera->get_fov() / 2.0; - Vector3 side = Vector3(Math::sin(Math::deg_to_rad(fov)), 0, -Math::cos(Math::deg_to_rad(fov))); - Vector3 nside = side; - nside.x = -nside.x; - Vector3 up = Vector3(0, side.x, 0); + const float hsize = Math::sin(Math::deg_to_rad(fov)); + const float depth = -Math::cos(Math::deg_to_rad(fov)); + Vector3 side = Vector3(hsize * size_factor.x, 0, depth); + Vector3 nside = Vector3(-side.x, side.y, side.z); + Vector3 up = Vector3(0, hsize * size_factor.y, 0); ADD_TRIANGLE(Vector3(), side + up, side - up); ADD_TRIANGLE(Vector3(), nside + up, nside - up); @@ -1868,18 +1892,18 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { ADD_TRIANGLE(Vector3(), side - up, nside - up); handles.push_back(side); - side.x *= 0.25; - nside.x *= 0.25; - Vector3 tup(0, up.y * 3 / 2, side.z); + side.x = MIN(side.x, hsize * 0.25); + nside.x = -side.x; + Vector3 tup(0, up.y + hsize / 2, side.z); ADD_TRIANGLE(tup, side + up, nside + up); - } break; + case Camera3D::PROJECTION_ORTHOGONAL: { float size = camera->get_size(); float hsize = size * 0.5; - Vector3 right(hsize, 0, 0); - Vector3 up(0, hsize, 0); + Vector3 right(hsize * size_factor.x, 0, 0); + Vector3 up(0, hsize * size_factor.y, 0); Vector3 back(0, 0, -1.0); Vector3 front(0, 0, 0); @@ -1890,18 +1914,19 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { handles.push_back(right + back); - right.x *= 0.25; - Vector3 tup(0, up.y * 3 / 2, back.z); + right.x = MIN(right.x, hsize * 0.25); + Vector3 tup(0, up.y + hsize / 2, back.z); ADD_TRIANGLE(tup, right + up + back, -right + up + back); } break; + case Camera3D::PROJECTION_FRUSTUM: { float hsize = camera->get_size() / 2.0; Vector3 side = Vector3(hsize, 0, -camera->get_near()).normalized(); - Vector3 nside = side; - nside.x = -nside.x; - Vector3 up = Vector3(0, side.x, 0); + side.x *= size_factor.x; + Vector3 nside = Vector3(-side.x, side.y, side.z); + Vector3 up = Vector3(0, hsize * size_factor.y, 0); Vector3 offset = Vector3(camera->get_frustum_offset().x, camera->get_frustum_offset().y, 0.0); ADD_TRIANGLE(Vector3(), side + up + offset, side - up + offset); @@ -1909,11 +1934,11 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { ADD_TRIANGLE(Vector3(), side + up + offset, nside + up + offset); ADD_TRIANGLE(Vector3(), side - up + offset, nside - up + offset); - side.x *= 0.25; - nside.x *= 0.25; - Vector3 tup(0, up.y * 3 / 2, side.z); + side.x = MIN(side.x, hsize * 0.25); + nside.x = -side.x; + Vector3 tup(0, up.y + hsize / 2, side.z); ADD_TRIANGLE(tup + offset, side + up + offset, nside + up + offset); - } + } break; } #undef ADD_TRIANGLE @@ -1921,7 +1946,10 @@ void Camera3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) { p_gizmo->add_lines(lines, material); p_gizmo->add_collision_segments(lines); - p_gizmo->add_handles(handles, get_material("handles")); + + if (!handles.is_empty()) { + p_gizmo->add_handles(handles, get_material("handles")); + } } ////// diff --git a/editor/plugins/node_3d_editor_gizmos.h b/editor/plugins/node_3d_editor_gizmos.h index d7e3e03f61..60d44ad787 100644 --- a/editor/plugins/node_3d_editor_gizmos.h +++ b/editor/plugins/node_3d_editor_gizmos.h @@ -264,6 +264,9 @@ public: class Camera3DGizmoPlugin : public EditorNode3DGizmoPlugin { GDCLASS(Camera3DGizmoPlugin, EditorNode3DGizmoPlugin); +private: + static Size2i _get_viewport_size(Camera3D *p_camera); + public: bool has_gizmo(Node3D *p_spatial) override; String get_gizmo_name() const override; diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp index ca6d65bd57..f5dd893377 100644 --- a/editor/plugins/node_3d_editor_plugin.cpp +++ b/editor/plugins/node_3d_editor_plugin.cpp @@ -36,14 +36,12 @@ #include "core/math/math_funcs.h" #include "core/math/projection.h" #include "core/os/keyboard.h" -#include "core/templates/sort_array.h" #include "editor/debugger/editor_debugger_node.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/node_3d_editor_gizmos.h" -#include "editor/plugins/script_editor_plugin.h" #include "editor/scene_tree_dock.h" #include "scene/3d/camera_3d.h" #include "scene/3d/collision_shape_3d.h" @@ -54,9 +52,12 @@ #include "scene/3d/visual_instance_3d.h" #include "scene/3d/world_environment.h" #include "scene/gui/center_container.h" +#include "scene/gui/color_picker.h" #include "scene/gui/flow_container.h" +#include "scene/gui/split_container.h" #include "scene/gui/subviewport_container.h" #include "scene/resources/packed_scene.h" +#include "scene/resources/sky_material.h" #include "scene/resources/surface_tool.h" constexpr real_t DISTANCE_DEFAULT = 4; @@ -85,6 +86,177 @@ constexpr real_t MAX_Z = 1000000.0; constexpr real_t MIN_FOV = 0.01; constexpr real_t MAX_FOV = 179; +void ViewportNavigationControl::_notification(int p_what) { + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + if (!is_connected("mouse_exited", callable_mp(this, &ViewportNavigationControl::_on_mouse_exited))) { + connect("mouse_exited", callable_mp(this, &ViewportNavigationControl::_on_mouse_exited)); + } + if (!is_connected("mouse_entered", callable_mp(this, &ViewportNavigationControl::_on_mouse_entered))) { + connect("mouse_entered", callable_mp(this, &ViewportNavigationControl::_on_mouse_entered)); + } + } break; + + case NOTIFICATION_DRAW: { + if (viewport != nullptr) { + _draw(); + _update_navigation(); + } + } break; + } +} + +void ViewportNavigationControl::_draw() { + if (nav_mode == Node3DEditorViewport::NAVIGATION_NONE) { + return; + } + + Vector2 center = get_size() / 2.0; + float radius = get_size().x / 2.0; + + const bool focused = focused_index != -1; + draw_circle(center, radius, Color(0.5, 0.5, 0.5, focused || hovered ? 0.35 : 0.15)); + + const Color c = focused ? Color(0.9, 0.9, 0.9, 0.9) : Color(0.5, 0.5, 0.5, 0.25); + + Vector2 circle_pos = focused ? center.move_toward(focused_pos, radius) : center; + + draw_circle(circle_pos, AXIS_CIRCLE_RADIUS, c); + draw_circle(circle_pos, AXIS_CIRCLE_RADIUS * 0.8, c.darkened(0.4)); +} + +void ViewportNavigationControl::_process_click(int p_index, Vector2 p_position, bool p_pressed) { + hovered = false; + queue_redraw(); + + if (focused_index != -1 && focused_index != p_index) { + return; + } + if (p_pressed) { + if (p_position.distance_to(get_size() / 2.0) < get_size().x / 2.0) { + focused_pos = p_position; + focused_index = p_index; + queue_redraw(); + } + } else { + focused_index = -1; + if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + Input::get_singleton()->warp_mouse(focused_mouse_start); + } + } +} + +void ViewportNavigationControl::_process_drag(int p_index, Vector2 p_position, Vector2 p_relative_position) { + if (focused_index == p_index) { + if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_VISIBLE) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + focused_mouse_start = p_position; + } + focused_pos += p_relative_position; + queue_redraw(); + } +} + +void ViewportNavigationControl::gui_input(const Ref<InputEvent> &p_event) { + // Mouse events + const Ref<InputEventMouseButton> mouse_button = p_event; + if (mouse_button.is_valid() && mouse_button->get_button_index() == MouseButton::LEFT) { + _process_click(100, mouse_button->get_position(), mouse_button->is_pressed()); + } + + const Ref<InputEventMouseMotion> mouse_motion = p_event; + if (mouse_motion.is_valid()) { + _process_drag(100, mouse_motion->get_global_position(), viewport->_get_warped_mouse_motion(mouse_motion)); + } + + // Touch events + const Ref<InputEventScreenTouch> screen_touch = p_event; + if (screen_touch.is_valid()) { + _process_click(screen_touch->get_index(), screen_touch->get_position(), screen_touch->is_pressed()); + } + + const Ref<InputEventScreenDrag> screen_drag = p_event; + if (screen_drag.is_valid()) { + _process_drag(screen_drag->get_index(), screen_drag->get_position(), screen_drag->get_relative()); + } +} + +void ViewportNavigationControl::_update_navigation() { + if (focused_index == -1) { + return; + } + + Vector2 delta = focused_pos - (get_size() / 2.0); + Vector2 delta_normalized = delta.normalized(); + switch (nav_mode) { + case Node3DEditorViewport::NavigationMode::NAVIGATION_MOVE: { + real_t speed_multiplier = MIN(delta.length() / (get_size().x * 100.0), 3.0); + real_t speed = viewport->freelook_speed * speed_multiplier; + + const Node3DEditorViewport::FreelookNavigationScheme navigation_scheme = (Node3DEditorViewport::FreelookNavigationScheme)EditorSettings::get_singleton()->get("editors/3d/freelook/freelook_navigation_scheme").operator int(); + + Vector3 forward; + if (navigation_scheme == Node3DEditorViewport::FreelookNavigationScheme::FREELOOK_FULLY_AXIS_LOCKED) { + // Forward/backward keys will always go straight forward/backward, never moving on the Y axis. + forward = Vector3(0, 0, delta_normalized.y).rotated(Vector3(0, 1, 0), viewport->camera->get_rotation().y); + } else { + // Forward/backward keys will be relative to the camera pitch. + forward = viewport->camera->get_transform().basis.xform(Vector3(0, 0, delta_normalized.y)); + } + + const Vector3 right = viewport->camera->get_transform().basis.xform(Vector3(delta_normalized.x, 0, 0)); + + const Vector3 direction = forward + right; + const Vector3 motion = direction * speed; + viewport->cursor.pos += motion; + viewport->cursor.eye_pos += motion; + } break; + + case Node3DEditorViewport::NavigationMode::NAVIGATION_LOOK: { + real_t speed_multiplier = MIN(delta.length() / (get_size().x * 2.5), 3.0); + real_t speed = viewport->freelook_speed * speed_multiplier; + viewport->_nav_look(nullptr, delta_normalized * speed); + } break; + + case Node3DEditorViewport::NAVIGATION_PAN: { + real_t speed_multiplier = MIN(delta.length() / (get_size().x), 3.0); + real_t speed = viewport->freelook_speed * speed_multiplier; + viewport->_nav_pan(nullptr, -delta_normalized * speed); + } break; + case Node3DEditorViewport::NAVIGATION_ZOOM: { + real_t speed_multiplier = MIN(delta.length() / (get_size().x), 3.0); + real_t speed = viewport->freelook_speed * speed_multiplier; + viewport->_nav_zoom(nullptr, delta_normalized * speed); + } break; + case Node3DEditorViewport::NAVIGATION_ORBIT: { + real_t speed_multiplier = MIN(delta.length() / (get_size().x), 3.0); + real_t speed = viewport->freelook_speed * speed_multiplier; + viewport->_nav_orbit(nullptr, delta_normalized * speed); + } break; + case Node3DEditorViewport::NAVIGATION_NONE: { + } break; + } +} + +void ViewportNavigationControl::_on_mouse_entered() { + hovered = true; + queue_redraw(); +} + +void ViewportNavigationControl::_on_mouse_exited() { + hovered = false; + queue_redraw(); +} + +void ViewportNavigationControl::set_navigation_mode(Node3DEditorViewport::NavigationMode p_nav_mode) { + nav_mode = p_nav_mode; +} + +void ViewportNavigationControl::set_viewport(Node3DEditorViewport *p_viewport) { + viewport = p_viewport; +} + void ViewportRotationControl::_notification(int p_what) { switch (p_what) { case NOTIFICATION_ENTER_TREE: { @@ -119,7 +291,7 @@ void ViewportRotationControl::_draw() { const Vector2i center = get_size() / 2.0; const real_t radius = get_size().x / 2.0; - if (focused_axis > -2 || orbiting) { + if (focused_axis > -2 || orbiting_index != -1) { draw_circle(center, radius, Color(0.5, 0.5, 0.5, 0.25)); } @@ -190,41 +362,63 @@ void ViewportRotationControl::_get_sorted_axis(Vector<Axis2D> &r_axis) { r_axis.sort_custom<Axis2DCompare>(); } +void ViewportRotationControl::_process_click(int p_index, Vector2 p_position, bool p_pressed) { + if (orbiting_index != -1 && orbiting_index != p_index) { + return; + } + if (p_pressed) { + if (p_position.distance_to(get_size() / 2.0) < get_size().x / 2.0) { + orbiting_index = p_index; + } + } else { + if (focused_axis > -1) { + viewport->_menu_option(axis_menu_options[focused_axis]); + _update_focus(); + } + orbiting_index = -1; + if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + Input::get_singleton()->warp_mouse(orbiting_mouse_start); + } + } +} + +void ViewportRotationControl::_process_drag(Ref<InputEventWithModifiers> p_event, int p_index, Vector2 p_position, Vector2 p_relative_position) { + if (orbiting_index == p_index) { + if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_VISIBLE) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); + orbiting_mouse_start = p_position; + } + viewport->_nav_orbit(p_event, p_relative_position); + focused_axis = -1; + } else { + _update_focus(); + } +} + void ViewportRotationControl::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); + // Mouse events const Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT) { - Vector2 pos = mb->get_position(); - if (mb->is_pressed()) { - if (pos.distance_to(get_size() / 2.0) < get_size().x / 2.0) { - orbiting = true; - } - } else { - if (focused_axis > -1) { - viewport->_menu_option(axis_menu_options[focused_axis]); - _update_focus(); - } - orbiting = false; - if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_CAPTURED) { - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); - Input::get_singleton()->warp_mouse(orbiting_mouse_start); - } - } + _process_click(100, mb->get_position(), mb->is_pressed()); } const Ref<InputEventMouseMotion> mm = p_event; if (mm.is_valid()) { - if (orbiting) { - if (Input::get_singleton()->get_mouse_mode() == Input::MOUSE_MODE_VISIBLE) { - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); - orbiting_mouse_start = mm->get_global_position(); - } - viewport->_nav_orbit(mm, viewport->_get_warped_mouse_motion(mm)); - focused_axis = -1; - } else { - _update_focus(); - } + _process_drag(mm, 100, mm->get_global_position(), viewport->_get_warped_mouse_motion(mm)); + } + + // Touch events + const Ref<InputEventScreenTouch> screen_touch = p_event; + if (screen_touch.is_valid()) { + _process_click(screen_touch->get_index(), screen_touch->get_position(), screen_touch->is_pressed()); + } + + const Ref<InputEventScreenDrag> screen_drag = p_event; + if (screen_drag.is_valid()) { + _process_drag(screen_drag, screen_drag->get_index(), screen_drag->get_position(), screen_drag->get_relative()); } } @@ -352,6 +546,8 @@ void Node3DEditorViewport::_update_camera(real_t p_interp_delta) { update_transform_gizmo_view(); rotation_control->queue_redraw(); + position_control->queue_redraw(); + look_control->queue_redraw(); spatial_editor->update_grid(); } } @@ -2090,7 +2286,7 @@ void Node3DEditorViewport::_nav_pan(Ref<InputEventWithModifiers> p_event, const const NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); real_t pan_speed = 1 / 150.0; - if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) { + if (p_event.is_valid() && nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) { pan_speed *= 10; } @@ -2114,7 +2310,7 @@ void Node3DEditorViewport::_nav_zoom(Ref<InputEventWithModifiers> p_event, const const NavigationScheme nav_scheme = (NavigationScheme)EDITOR_GET("editors/3d/navigation/navigation_scheme").operator int(); real_t zoom_speed = 1 / 80.0; - if (nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) { + if (p_event.is_valid() && nav_scheme == NAVIGATION_MAYA && p_event->is_shift_pressed()) { zoom_speed *= 10; } @@ -2447,6 +2643,8 @@ void Node3DEditorViewport::_notification(int p_what) { } call_deferred(SNAME("update_transform_gizmo_view")); rotation_control->set_visible(EDITOR_GET("editors/3d/navigation/show_viewport_rotation_gizmo")); + position_control->set_visible(EDITOR_GET("editors/3d/navigation/show_viewport_navigation_gizmo")); + look_control->set_visible(EDITOR_GET("editors/3d/navigation/show_viewport_navigation_gizmo")); } break; case NOTIFICATION_RESIZED: { @@ -3369,6 +3567,8 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { ERR_FAIL_COND(!p_activate && !previewing); rotation_control->set_visible(!p_activate); + position_control->set_visible(!p_activate); + look_control->set_visible(!p_activate); if (!p_activate) { previewing->disconnect("tree_exiting", callable_mp(this, &Node3DEditorViewport::_preview_exited_scene)); @@ -3390,6 +3590,8 @@ void Node3DEditorViewport::_toggle_camera_preview(bool p_activate) { void Node3DEditorViewport::_toggle_cinema_preview(bool p_activate) { previewing_cinema = p_activate; rotation_control->set_visible(!p_activate); + position_control->set_visible(!p_activate); + look_control->set_visible(!p_activate); if (!previewing_cinema) { if (previewing != nullptr) { @@ -4873,6 +5075,14 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p preview_node = nullptr; + bottom_center_vbox = memnew(VBoxContainer); + bottom_center_vbox->set_anchors_preset(LayoutPreset::PRESET_CENTER); + bottom_center_vbox->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -20 * EDSCALE); + bottom_center_vbox->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE); + bottom_center_vbox->set_h_grow_direction(GROW_DIRECTION_BOTH); + bottom_center_vbox->set_v_grow_direction(GROW_DIRECTION_BEGIN); + surface->add_child(bottom_center_vbox); + info_label = memnew(Label); info_label->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -90 * EDSCALE); info_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -90 * EDSCALE); @@ -4893,23 +5103,18 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p previewing_cinema = false; locked_label = memnew(Label); - locked_label->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -20 * EDSCALE); - locked_label->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, -10 * EDSCALE); - locked_label->set_h_grow_direction(GROW_DIRECTION_END); - locked_label->set_v_grow_direction(GROW_DIRECTION_BEGIN); locked_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - surface->add_child(locked_label); + locked_label->set_h_size_flags(SIZE_SHRINK_CENTER); + bottom_center_vbox->add_child(locked_label); locked_label->set_text(TTR("View Rotation Locked")); locked_label->hide(); zoom_limit_label = memnew(Label); - zoom_limit_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); - zoom_limit_label->set_offset(Side::SIDE_TOP, -28 * EDSCALE); zoom_limit_label->set_text(TTR("To zoom further, change the camera's clipping planes (View -> Settings...)")); zoom_limit_label->set_name("ZoomLimitMessageLabel"); zoom_limit_label->add_theme_color_override("font_color", Color(1, 1, 1, 1)); zoom_limit_label->hide(); - surface->add_child(zoom_limit_label); + bottom_center_vbox->add_child(zoom_limit_label); preview_material_label = memnew(Label); preview_material_label->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT); @@ -4940,6 +5145,30 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p // Prevent visible spacing between frame time labels. top_right_vbox->add_theme_constant_override("separation", 0); + const int navigation_control_size = 150; + + position_control = memnew(ViewportNavigationControl); + position_control->set_navigation_mode(Node3DEditorViewport::NAVIGATION_MOVE); + position_control->set_custom_minimum_size(Size2(navigation_control_size, navigation_control_size) * EDSCALE); + position_control->set_h_size_flags(SIZE_SHRINK_END); + position_control->set_anchor_and_offset(SIDE_LEFT, ANCHOR_BEGIN, 0 * EDSCALE); + position_control->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -navigation_control_size * EDSCALE); + position_control->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_BEGIN, navigation_control_size * EDSCALE); + position_control->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0 * EDSCALE); + position_control->set_viewport(this); + surface->add_child(position_control); + + look_control = memnew(ViewportNavigationControl); + look_control->set_navigation_mode(Node3DEditorViewport::NAVIGATION_LOOK); + look_control->set_custom_minimum_size(Size2(navigation_control_size, navigation_control_size) * EDSCALE); + look_control->set_h_size_flags(SIZE_SHRINK_END); + look_control->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -navigation_control_size * EDSCALE); + look_control->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -navigation_control_size * EDSCALE); + look_control->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0 * EDSCALE); + look_control->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0 * EDSCALE); + look_control->set_viewport(this); + surface->add_child(look_control); + rotation_control = memnew(ViewportRotationControl); rotation_control->set_custom_minimum_size(Size2(80, 80) * EDSCALE); rotation_control->set_h_size_flags(SIZE_SHRINK_END); @@ -7248,6 +7477,8 @@ void Node3DEditor::_notification(int p_what) { sun_state->set_custom_minimum_size(sun_vb->get_combined_minimum_size()); environ_state->set_custom_minimum_size(environ_vb->get_combined_minimum_size()); + + EditorNode::get_singleton()->connect("project_settings_changed", callable_mp(this, &Node3DEditor::update_all_gizmos).bind(Variant())); } break; case NOTIFICATION_ENTER_TREE: { @@ -7408,6 +7639,13 @@ void Node3DEditor::_request_gizmo(Object *p_obj) { } } +void Node3DEditor::_request_gizmo_for_id(ObjectID p_id) { + Node3D *node = Object::cast_to<Node3D>(ObjectDB::get_instance(p_id)); + if (node) { + _request_gizmo(node); + } +} + void Node3DEditor::_set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform) { if (p_id == -1) { _clear_subgizmo_selection(p_obj); @@ -7588,6 +7826,7 @@ void Node3DEditor::_register_all_gizmos() { void Node3DEditor::_bind_methods() { ClassDB::bind_method("_get_editor_data", &Node3DEditor::_get_editor_data); ClassDB::bind_method("_request_gizmo", &Node3DEditor::_request_gizmo); + ClassDB::bind_method("_request_gizmo_for_id", &Node3DEditor::_request_gizmo_for_id); ClassDB::bind_method("_set_subgizmo_selection", &Node3DEditor::_set_subgizmo_selection); ClassDB::bind_method("_clear_subgizmo_selection", &Node3DEditor::_clear_subgizmo_selection); ClassDB::bind_method("_refresh_menu_icons", &Node3DEditor::_refresh_menu_icons); @@ -8190,7 +8429,8 @@ Node3DEditor::Node3DEditor() { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::INT, "editors/3d/manipulator_gizmo_size", PROPERTY_HINT_RANGE, "16,160,1")); EDITOR_DEF("editors/3d/manipulator_gizmo_opacity", 0.9); EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::FLOAT, "editors/3d/manipulator_gizmo_opacity", PROPERTY_HINT_RANGE, "0,1,0.01")); - EDITOR_DEF("editors/3d/navigation/show_viewport_rotation_gizmo", true); + EDITOR_DEF_RST("editors/3d/navigation/show_viewport_rotation_gizmo", true); + EDITOR_DEF_RST("editors/3d/navigation/show_viewport_navigation_gizmo", DisplayServer::get_singleton()->is_touchscreen_available()); current_hover_gizmo_handle = -1; current_hover_gizmo_handle_secondary = false; diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h index a8d3bfb70c..fc252822c4 100644 --- a/editor/plugins/node_3d_editor_plugin.h +++ b/editor/plugins/node_3d_editor_plugin.h @@ -33,32 +33,31 @@ #include "editor/editor_plugin.h" #include "editor/editor_scale.h" -#include "editor/editor_spin_slider.h" #include "editor/plugins/node_3d_editor_gizmos.h" -#include "scene/3d/camera_3d.h" -#include "scene/3d/light_3d.h" -#include "scene/3d/visual_instance_3d.h" -#include "scene/3d/world_environment.h" #include "scene/gui/box_container.h" -#include "scene/gui/color_picker.h" -#include "scene/gui/panel_container.h" +#include "scene/gui/button.h" #include "scene/gui/spin_box.h" -#include "scene/gui/split_container.h" -#include "scene/resources/environment.h" -#include "scene/resources/fog_material.h" -#include "scene/resources/sky_material.h" class AcceptDialog; class CheckBox; +class ColorPickerButton; class ConfirmationDialog; +class DirectionalLight3D; class EditorData; +class EditorSpinSlider; +class HSplitContainer; +class LineEdit; class MenuButton; class Node3DEditor; class Node3DEditorViewport; class OptionButton; +class PanelContainer; +class ProceduralSkyMaterial; +class SubViewport; class SubViewportContainer; -class DirectionalLight3D; +class VSplitContainer; class WorldEnvironment; +class ViewportNavigationControl; class ViewportRotationControl : public Control { GDCLASS(ViewportRotationControl, Control); @@ -79,7 +78,7 @@ class ViewportRotationControl : public Control { Vector<Color> axis_colors; Vector<int> axis_menu_options; Vector2i orbiting_mouse_start; - bool orbiting = false; + int orbiting_index = -1; int focused_axis = -2; const float AXIS_CIRCLE_RADIUS = 8.0f * EDSCALE; @@ -92,6 +91,8 @@ protected: void _get_sorted_axis(Vector<Axis2D> &r_axis); void _update_focus(); void _on_mouse_exited(); + void _process_click(int p_index, Vector2 p_position, bool p_pressed); + void _process_drag(Ref<InputEventWithModifiers> p_event, int p_index, Vector2 p_position, Vector2 p_relative_position); public: void set_viewport(Node3DEditorViewport *p_viewport); @@ -100,6 +101,7 @@ public: class Node3DEditorViewport : public Control { GDCLASS(Node3DEditorViewport, Control); friend class Node3DEditor; + friend class ViewportNavigationControl; friend class ViewportRotationControl; enum { VIEW_TOP, @@ -238,6 +240,9 @@ private: Label *preview_material_label_desc = nullptr; VBoxContainer *top_right_vbox = nullptr; + VBoxContainer *bottom_center_vbox = nullptr; + ViewportNavigationControl *position_control = nullptr; + ViewportNavigationControl *look_control = nullptr; ViewportRotationControl *rotation_control = nullptr; Gradient *frame_time_gradient = nullptr; Label *cpu_time_label = nullptr; @@ -299,7 +304,8 @@ private: NAVIGATION_PAN, NAVIGATION_ZOOM, NAVIGATION_ORBIT, - NAVIGATION_LOOK + NAVIGATION_LOOK, + NAVIGATION_MOVE }; enum TransformMode { TRANSFORM_NONE, @@ -710,6 +716,7 @@ private: Node3D *selected = nullptr; void _request_gizmo(Object *p_obj); + void _request_gizmo_for_id(ObjectID p_id); void _set_subgizmo_selection(Object *p_obj, Ref<Node3DGizmo> p_gizmo, int p_id, Transform3D p_transform = Transform3D()); void _clear_subgizmo_selection(Object *p_obj = nullptr); @@ -918,4 +925,31 @@ public: ~Node3DEditorPlugin(); }; +class ViewportNavigationControl : public Control { + GDCLASS(ViewportNavigationControl, Control); + + Node3DEditorViewport *viewport = nullptr; + Vector2i focused_mouse_start; + Vector2 focused_pos; + bool hovered = false; + int focused_index = -1; + Node3DEditorViewport::NavigationMode nav_mode = Node3DEditorViewport::NavigationMode::NAVIGATION_NONE; + + const float AXIS_CIRCLE_RADIUS = 30.0f * EDSCALE; + +protected: + void _notification(int p_what); + virtual void gui_input(const Ref<InputEvent> &p_event) override; + void _draw(); + void _on_mouse_entered(); + void _on_mouse_exited(); + void _process_click(int p_index, Vector2 p_position, bool p_pressed); + void _process_drag(int p_index, Vector2 p_position, Vector2 p_relative_position); + void _update_navigation(); + +public: + void set_navigation_mode(Node3DEditorViewport::NavigationMode p_nav_mode); + void set_viewport(Node3DEditorViewport *p_viewport); +}; + #endif // NODE_3D_EDITOR_PLUGIN_H diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 133a7e5327..3204cc8d0f 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/menu_button.h" void Path2DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp index d7953bf4e0..63ca78d6c0 100644 --- a/editor/plugins/path_3d_editor_plugin.cpp +++ b/editor/plugins/path_3d_editor_plugin.cpp @@ -37,6 +37,7 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" +#include "scene/gui/menu_button.h" #include "scene/resources/curve.h" static bool _is_in_handle(int p_id, int p_num_points) { @@ -239,38 +240,63 @@ void Path3DGizmo::redraw() { return; } - Vector<Vector3> v3a = c->tessellate(); - //Vector<Vector3> v3a=c->get_baked_points(); + real_t interval = 0.1; + const real_t length = c->get_baked_length(); - int v3s = v3a.size(); - if (v3s == 0) { - return; - } - Vector<Vector3> v3p; - const Vector3 *r = v3a.ptr(); - - // BUG: the following won't work when v3s, avoid drawing as a temporary workaround. - for (int i = 0; i < v3s - 1; i++) { - v3p.push_back(r[i]); - v3p.push_back(r[i + 1]); - //v3p.push_back(r[i]); - //v3p.push_back(r[i]+Vector3(0,0.2,0)); - } + // 1. Draw curve and bones. + if (length > CMP_EPSILON) { + const int sample_count = int(length / interval) + 2; + interval = length / (sample_count - 1); // Recalculate real interval length. + + Vector<Transform3D> frames; + frames.resize(sample_count); + + { + Transform3D *w = frames.ptrw(); + + for (int i = 0; i < sample_count; i++) { + w[i] = c->sample_baked_with_rotation(i * interval, true, true); + } + } + + const Transform3D *r = frames.ptr(); + Vector<Vector3> v3p; + for (int i = 0; i < sample_count - 1; i++) { + const Vector3 p1 = r[i].origin; + const Vector3 p2 = r[i + 1].origin; + const Vector3 side = r[i].basis.get_column(0); + const Vector3 up = r[i].basis.get_column(1); + const Vector3 forward = r[i].basis.get_column(2); + + // Curve segment. + v3p.push_back(p1); + v3p.push_back(p2); + + // Fish Bone. + v3p.push_back(p1); + v3p.push_back(p1 + (side - forward) * 0.06); + + v3p.push_back(p1); + v3p.push_back(p1 + (-side - forward) * 0.06); + + v3p.push_back(p1); + v3p.push_back(p1 + up * 0.03); + } - if (v3p.size() > 1) { add_lines(v3p, path_material); add_collision_segments(v3p); } + // 2. Draw handles. if (Path3DEditorPlugin::singleton->get_edited_path() == path) { - v3p.clear(); + Vector<Vector3> v3p; Vector<Vector3> handle_points; Vector<Vector3> sec_handle_points; for (int i = 0; i < c->get_point_count(); i++) { Vector3 p = c->get_point_position(i); handle_points.push_back(p); - // push Out points first so they get selected if the In and Out points are on top of each other. + // Push out points first so they get selected if the In and Out points are on top of each other. if (i < c->get_point_count() - 1) { v3p.push_back(p); v3p.push_back(p + c->get_point_out(i)); diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp index 9dc89133c4..2b59e4cf08 100644 --- a/editor/plugins/physical_bone_3d_editor_plugin.cpp +++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "physical_bone_3d_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" +#include "scene/gui/separator.h" void PhysicalBone3DEditor::_bind_methods() { } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 6218c887fb..a19a42f951 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -38,10 +38,14 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/skeleton_2d.h" +#include "scene/gui/check_box.h" #include "scene/gui/menu_button.h" #include "scene/gui/scroll_container.h" #include "scene/gui/separator.h" #include "scene/gui/slider.h" +#include "scene/gui/spin_box.h" +#include "scene/gui/split_container.h" +#include "scene/gui/texture_rect.h" #include "scene/gui/view_panner.h" Node2D *Polygon2DEditor::_get_node() const { diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp index 1cd4804b79..dde44d31fa 100644 --- a/editor/plugins/polygon_3d_editor_plugin.cpp +++ b/editor/plugins/polygon_3d_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "editor/editor_undo_redo_manager.h" #include "node_3d_editor_plugin.h" #include "scene/3d/camera_3d.h" +#include "scene/gui/separator.h" void Polygon3DEditor::_notification(int p_what) { switch (p_what) { diff --git a/editor/plugins/root_motion_editor_plugin.cpp b/editor/plugins/root_motion_editor_plugin.cpp index 596b2c0edb..93a64a8f3d 100644 --- a/editor/plugins/root_motion_editor_plugin.cpp +++ b/editor/plugins/root_motion_editor_plugin.cpp @@ -32,6 +32,7 @@ #include "editor/editor_node.h" #include "scene/animation/animation_player.h" #include "scene/animation/animation_tree.h" +#include "scene/gui/tree.h" #include "scene/main/window.h" void EditorPropertyRootMotion::_confirmed() { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 4ff3919e9b..bb5491fcb5 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -40,6 +40,7 @@ #include "editor/debugger/editor_debugger_node.h" #include "editor/debugger/script_editor_debugger.h" #include "editor/editor_file_dialog.h" +#include "editor/editor_help_search.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" #include "editor/editor_run_script.h" @@ -47,6 +48,7 @@ #include "editor/editor_settings.h" #include "editor/filesystem_dock.h" #include "editor/find_in_files.h" +#include "editor/inspector_dock.h" #include "editor/node_dock.h" #include "editor/plugins/shader_editor_plugin.h" #include "editor/plugins/text_shader_editor.h" diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 3f84ded0a2..213fbdc22a 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -31,24 +31,22 @@ #ifndef SCRIPT_EDITOR_PLUGIN_H #define SCRIPT_EDITOR_PLUGIN_H -#include "core/object/script_language.h" -#include "editor/code_editor.h" -#include "editor/editor_help.h" -#include "editor/editor_help_search.h" #include "editor/editor_plugin.h" -#include "editor/script_create_dialog.h" -#include "scene/gui/item_list.h" -#include "scene/gui/line_edit.h" -#include "scene/gui/menu_button.h" -#include "scene/gui/split_container.h" -#include "scene/gui/tab_container.h" -#include "scene/gui/text_edit.h" -#include "scene/gui/tree.h" -#include "scene/main/timer.h" +#include "scene/gui/dialogs.h" +#include "scene/gui/panel_container.h" +#include "scene/resources/syntax_highlighter.h" #include "scene/resources/text_file.h" class EditorFileDialog; +class EditorHelpSearch; +class FindReplaceBar; +class HSplitContainer; +class ItemList; +class MenuButton; +class TabContainer; class TextureRect; +class Tree; +class VSplitContainer; class EditorSyntaxHighlighter : public SyntaxHighlighter { GDCLASS(EditorSyntaxHighlighter, SyntaxHighlighter) diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 4e66dc3d7e..38639ac811 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "scene/gui/split_container.h" void ConnectionInfoDialog::ok_pressed() { } @@ -1222,7 +1223,9 @@ void ScriptTextEditor::_edit_option(int p_op) { code_editor->duplicate_selection(); } break; case EDIT_TOGGLE_FOLD_LINE: { - tx->toggle_foldable_line(tx->get_caret_line()); + for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) { + tx->toggle_foldable_line(tx->get_caret_line(caret_idx)); + } tx->queue_redraw(); } break; case EDIT_FOLD_ALL_LINES: { @@ -1290,28 +1293,28 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_EVALUATE: { Expression expression; - Vector<String> lines = code_editor->get_text_editor()->get_selected_text().split("\n"); - PackedStringArray results; - - for (int i = 0; i < lines.size(); i++) { - String line = lines[i]; - String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); //extract the whitespace at the beginning - - if (expression.parse(line) == OK) { - Variant result = expression.execute(Array(), Variant(), false, true); - if (expression.get_error_text().is_empty()) { - results.push_back(whitespace + result.get_construct_string()); + tx->begin_complex_operation(); + for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) { + Vector<String> lines = tx->get_selected_text(caret_idx).split("\n"); + PackedStringArray results; + + for (int i = 0; i < lines.size(); i++) { + String line = lines[i]; + String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); // Extract the whitespace at the beginning. + if (expression.parse(line) == OK) { + Variant result = expression.execute(Array(), Variant(), false, true); + if (expression.get_error_text().is_empty()) { + results.push_back(whitespace + result.get_construct_string()); + } else { + results.push_back(line); + } } else { results.push_back(line); } - } else { - results.push_back(line); } + tx->insert_text_at_caret(String("\n").join(results), caret_idx); } - - code_editor->get_text_editor()->begin_complex_operation(); //prevents creating a two-step undo - code_editor->get_text_editor()->insert_text_at_caret(String("\n").join(results)); - code_editor->get_text_editor()->end_complex_operation(); + tx->end_complex_operation(); } break; case SEARCH_FIND: { code_editor->get_find_replace_bar()->popup_search(); @@ -1326,14 +1329,14 @@ void ScriptTextEditor::_edit_option(int p_op) { code_editor->get_find_replace_bar()->popup_replace(); } break; case SEARCH_IN_FILES: { - String selected_text = code_editor->get_text_editor()->get_selected_text(); + String selected_text = tx->get_selected_text(); // Yep, because it doesn't make sense to instance this dialog for every single script open... // So this will be delegated to the ScriptEditor. emit_signal(SNAME("search_in_files_requested"), selected_text); } break; case REPLACE_IN_FILES: { - String selected_text = code_editor->get_text_editor()->get_selected_text(); + String selected_text = tx->get_selected_text(); emit_signal(SNAME("replace_in_files_requested"), selected_text); } break; @@ -1357,10 +1360,12 @@ void ScriptTextEditor::_edit_option(int p_op) { code_editor->remove_all_bookmarks(); } break; case DEBUG_TOGGLE_BREAKPOINT: { - int line = tx->get_caret_line(); - bool dobreak = !tx->is_line_breakpointed(line); - tx->set_line_as_breakpoint(line, dobreak); - EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak); + for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) { + int line = tx->get_caret_line(caret_idx); + bool dobreak = !tx->is_line_breakpointed(line); + tx->set_line_as_breakpoint(line, dobreak); + EditorDebuggerNode::get_singleton()->set_breakpoint(script->get_path(), line + 1, dobreak); + } } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { PackedInt32Array bpoints = tx->get_breakpointed_lines(); @@ -1378,26 +1383,14 @@ void ScriptTextEditor::_edit_option(int p_op) { return; } - tx->remove_secondary_carets(); - int line = tx->get_caret_line(); - - // wrap around - if (line >= (int)bpoints[bpoints.size() - 1]) { - tx->unfold_line(bpoints[0]); - tx->set_caret_line(bpoints[0]); - tx->center_viewport_to_caret(); - } else { - for (int i = 0; i < bpoints.size(); i++) { - int bline = bpoints[i]; - if (bline > line) { - tx->unfold_line(bline); - tx->set_caret_line(bline); - tx->center_viewport_to_caret(); - return; - } + int current_line = tx->get_caret_line(); + int bpoint_idx = 0; + if (current_line < (int)bpoints[bpoints.size() - 1]) { + while (bpoint_idx < bpoints.size() && bpoints[bpoint_idx] <= current_line) { + bpoint_idx++; } } - + code_editor->goto_line_centered(bpoints[bpoint_idx]); } break; case DEBUG_GOTO_PREV_BREAKPOINT: { PackedInt32Array bpoints = tx->get_breakpointed_lines(); @@ -1405,25 +1398,14 @@ void ScriptTextEditor::_edit_option(int p_op) { return; } - tx->remove_secondary_carets(); - int line = tx->get_caret_line(); - // wrap around - if (line <= (int)bpoints[0]) { - tx->unfold_line(bpoints[bpoints.size() - 1]); - tx->set_caret_line(bpoints[bpoints.size() - 1]); - tx->center_viewport_to_caret(); - } else { - for (int i = bpoints.size() - 1; i >= 0; i--) { - int bline = bpoints[i]; - if (bline < line) { - tx->unfold_line(bline); - tx->set_caret_line(bline); - tx->center_viewport_to_caret(); - return; - } + int current_line = tx->get_caret_line(); + int bpoint_idx = bpoints.size() - 1; + if (current_line > (int)bpoints[0]) { + while (bpoint_idx >= 0 && bpoints[bpoint_idx] >= current_line) { + bpoint_idx--; } } - + code_editor->goto_line_centered(bpoints[bpoint_idx]); } break; case HELP_CONTEXTUAL: { String text = tx->get_selected_text(0); @@ -1834,7 +1816,7 @@ void ScriptTextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { base = _find_node_for_script(base, base, script); } ScriptLanguage::LookupResult result; - if (script->get_language()->lookup_code(code_editor->get_text_editor()->get_text_for_symbol_lookup(), word_at_pos, script->get_path(), base, result) == OK) { + if (script->get_language()->lookup_code(tx->get_text_for_symbol_lookup(), word_at_pos, script->get_path(), base, result) == OK) { open_docs = true; } } diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 5fd12674b3..cbc4153e12 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -31,10 +31,14 @@ #ifndef SCRIPT_TEXT_EDITOR_H #define SCRIPT_TEXT_EDITOR_H +#include "script_editor_plugin.h" + +#include "editor/code_editor.h" #include "scene/gui/color_picker.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" -#include "script_editor_plugin.h" + +class RichTextLabel; class ConnectionInfoDialog : public AcceptDialog { GDCLASS(ConnectionInfoDialog, AcceptDialog); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 2f80e41dd4..fbc94c70f8 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -34,9 +34,12 @@ #include "editor/editor_scale.h" #include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" +#include "editor/inspector_dock.h" #include "editor/plugins/text_shader_editor.h" #include "editor/plugins/visual_shader_editor_plugin.h" #include "editor/shader_create_dialog.h" +#include "scene/gui/item_list.h" +#include "scene/gui/texture_rect.h" void ShaderEditorPlugin::_update_shader_list() { shader_list->clear(); diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h index 1ae419053e..4f0894a1a9 100644 --- a/editor/plugins/shader_editor_plugin.h +++ b/editor/plugins/shader_editor_plugin.h @@ -96,6 +96,7 @@ protected: static void _bind_methods(); public: + virtual String get_name() const override { return "Shader"; } virtual void edit(Object *p_object) override; virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; diff --git a/editor/plugins/shader_file_editor_plugin.cpp b/editor/plugins/shader_file_editor_plugin.cpp index dd644cb369..4e33c421ae 100644 --- a/editor/plugins/shader_file_editor_plugin.cpp +++ b/editor/plugins/shader_file_editor_plugin.cpp @@ -37,6 +37,8 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" +#include "scene/gui/item_list.h" +#include "scene/gui/split_container.h" #include "servers/display_server.h" #include "servers/rendering/shader_types.h" diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp index dbad81d743..5ae21a430d 100644 --- a/editor/plugins/skeleton_2d_editor_plugin.cpp +++ b/editor/plugins/skeleton_2d_editor_plugin.cpp @@ -35,6 +35,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/2d/mesh_instance_2d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" #include "thirdparty/misc/clipper.hpp" void Skeleton2DEditor::_node_removed(Node *p_node) { diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp index 8e80d0d5d8..f79a001efb 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.cpp +++ b/editor/plugins/skeleton_3d_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "node_3d_editor_plugin.h" @@ -41,10 +42,12 @@ #include "scene/3d/joint_3d.h" #include "scene/3d/mesh_instance_3d.h" #include "scene/3d/physics_body_3d.h" +#include "scene/gui/separator.h" #include "scene/resources/capsule_shape_3d.h" #include "scene/resources/skeleton_profile.h" #include "scene/resources/sphere_shape_3d.h" #include "scene/resources/surface_tool.h" +#include "scene/scene_string_names.h" void BoneTransformEditor::create_editors() { const Color section_color = get_theme_color(SNAME("prop_subsection"), SNAME("Editor")); @@ -397,8 +400,8 @@ void Skeleton3DEditor::create_physical_skeleton() { ur->add_do_method(physical_bone, "set_joint_type", PhysicalBone3D::JOINT_TYPE_PIN); } - ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", physical_bone); - ur->add_do_method(Node3DEditor::get_singleton(), "_request_gizmo", collision_shape); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, physical_bone); + ur->add_do_method(Node3DEditor::get_singleton(), SceneStringNames::get_singleton()->_request_gizmo, collision_shape); ur->add_do_reference(physical_bone); ur->add_undo_method(skeleton, "remove_child", physical_bone); diff --git a/editor/plugins/skeleton_3d_editor_plugin.h b/editor/plugins/skeleton_3d_editor_plugin.h index 273bdeaac8..8ef61861d0 100644 --- a/editor/plugins/skeleton_3d_editor_plugin.h +++ b/editor/plugins/skeleton_3d_editor_plugin.h @@ -45,6 +45,9 @@ class Joint; class PhysicalBone3D; class Skeleton3DEditorPlugin; class Button; +class Tree; +class TreeItem; +class VSeparator; class BoneTransformEditor : public VBoxContainer { GDCLASS(BoneTransformEditor, VBoxContainer); diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp index b78b70cd5c..110ad7cac0 100644 --- a/editor/plugins/sprite_2d_editor_plugin.cpp +++ b/editor/plugins/sprite_2d_editor_plugin.cpp @@ -41,6 +41,7 @@ #include "scene/2d/mesh_instance_2d.h" #include "scene/2d/polygon_2d.h" #include "scene/gui/box_container.h" +#include "scene/gui/menu_button.h" #include "thirdparty/misc/clipper.hpp" void Sprite2DEditor::_node_removed(Node *p_node) { diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp index 6924cb58bf..64e899b121 100644 --- a/editor/plugins/sprite_frames_editor_plugin.cpp +++ b/editor/plugins/sprite_frames_editor_plugin.cpp @@ -34,6 +34,7 @@ #include "core/io/resource_loader.h" #include "core/os/keyboard.h" #include "editor/editor_file_dialog.h" +#include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" @@ -43,6 +44,7 @@ #include "scene/gui/center_container.h" #include "scene/gui/margin_container.h" #include "scene/gui/panel_container.h" +#include "scene/gui/separator.h" static void _draw_shadowed_line(Control *p_control, const Point2 &p_from, const Size2 &p_size, const Size2 &p_shadow_offset, Color p_color, Color p_shadow_color) { p_control->draw_line(p_from, p_from + p_size, p_color); diff --git a/editor/plugins/style_box_editor_plugin.cpp b/editor/plugins/style_box_editor_plugin.cpp index 16a6a48df9..afc54a2b83 100644 --- a/editor/plugins/style_box_editor_plugin.cpp +++ b/editor/plugins/style_box_editor_plugin.cpp @@ -31,6 +31,7 @@ #include "style_box_editor_plugin.h" #include "editor/editor_scale.h" +#include "scene/gui/texture_button.h" bool StyleBoxPreview::grid_preview_enabled = true; diff --git a/editor/plugins/style_box_editor_plugin.h b/editor/plugins/style_box_editor_plugin.h index a072745d8f..d5351d3f34 100644 --- a/editor/plugins/style_box_editor_plugin.h +++ b/editor/plugins/style_box_editor_plugin.h @@ -37,6 +37,8 @@ #include "scene/gui/texture_rect.h" #include "scene/resources/style_box.h" +class TextureButton; + class StyleBoxPreview : public VBoxContainer { GDCLASS(StyleBoxPreview, VBoxContainer); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index 03cff74bdb..d6079d6285 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -33,6 +33,7 @@ #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" +#include "scene/gui/menu_button.h" void TextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { ERR_FAIL_COND(p_highlighter.is_null()); @@ -352,7 +353,9 @@ void TextEditor::_edit_option(int p_op) { code_editor->duplicate_selection(); } break; case EDIT_TOGGLE_FOLD_LINE: { - tx->toggle_foldable_line(tx->get_caret_line()); + for (int caret_idx = 0; caret_idx < tx->get_caret_count(); caret_idx++) { + tx->toggle_foldable_line(tx->get_caret_line(caret_idx)); + } tx->queue_redraw(); } break; case EDIT_FOLD_ALL_LINES: { diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 486a0f2c23..9f2132bc0b 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -33,6 +33,8 @@ #include "script_editor_plugin.h" +#include "editor/code_editor.h" + class TextEditor : public ScriptEditorBase { GDCLASS(TextEditor, ScriptEditorBase); diff --git a/editor/plugins/texture_3d_editor_plugin.cpp b/editor/plugins/texture_3d_editor_plugin.cpp index 4b2f28658a..bdea12c2cb 100644 --- a/editor/plugins/texture_3d_editor_plugin.cpp +++ b/editor/plugins/texture_3d_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "texture_3d_editor_plugin.h" +#include "scene/gui/label.h" + void Texture3DEditor::_texture_rect_draw() { texture_rect->draw_rect(Rect2(Point2(), texture_rect->get_size()), Color(1, 1, 1, 1)); } diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp index 4aed7a92a2..5783912c96 100644 --- a/editor/plugins/texture_editor_plugin.cpp +++ b/editor/plugins/texture_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "texture_editor_plugin.h" #include "editor/editor_scale.h" +#include "scene/gui/label.h" +#include "scene/gui/texture_rect.h" TextureRect *TexturePreview::get_texture_display() { return texture_display; diff --git a/editor/plugins/texture_layered_editor_plugin.cpp b/editor/plugins/texture_layered_editor_plugin.cpp index b0a174c1bc..479e84682b 100644 --- a/editor/plugins/texture_layered_editor_plugin.cpp +++ b/editor/plugins/texture_layered_editor_plugin.cpp @@ -30,6 +30,8 @@ #include "texture_layered_editor_plugin.h" +#include "scene/gui/label.h" + void TextureLayeredEditor::gui_input(const Ref<InputEvent> &p_event) { ERR_FAIL_COND(p_event.is_null()); diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp index 2e84a4fac9..fdfa3f8d0a 100644 --- a/editor/plugins/texture_region_editor_plugin.cpp +++ b/editor/plugins/texture_region_editor_plugin.cpp @@ -38,7 +38,9 @@ #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/gui/check_box.h" +#include "scene/gui/option_button.h" #include "scene/gui/separator.h" +#include "scene/gui/spin_box.h" #include "scene/gui/view_panner.h" #include "scene/resources/texture.h" diff --git a/editor/plugins/texture_region_editor_plugin.h b/editor/plugins/texture_region_editor_plugin.h index 310de19cc5..90a5b20e14 100644 --- a/editor/plugins/texture_region_editor_plugin.h +++ b/editor/plugins/texture_region_editor_plugin.h @@ -36,6 +36,7 @@ #include "editor/editor_plugin.h" #include "scene/2d/sprite_2d.h" #include "scene/3d/sprite_3d.h" +#include "scene/gui/dialogs.h" #include "scene/gui/nine_patch_rect.h" #include "scene/resources/style_box.h" #include "scene/resources/texture.h" diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 5d02e4e437..135b218768 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -38,6 +38,8 @@ #include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" #include "scene/gui/color_picker.h" +#include "scene/gui/panel_container.h" +#include "scene/gui/split_container.h" #include "scene/theme/theme_db.h" void ThemeItemImportTree::_update_items_tree() { diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp index fdd8a80ad3..082b21bbe5 100644 --- a/editor/plugins/theme_editor_preview.cpp +++ b/editor/plugins/theme_editor_preview.cpp @@ -36,9 +36,12 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" #include "scene/gui/button.h" +#include "scene/gui/check_box.h" #include "scene/gui/check_button.h" #include "scene/gui/color_picker.h" #include "scene/gui/progress_bar.h" +#include "scene/gui/text_edit.h" +#include "scene/gui/tree.h" #include "scene/resources/packed_scene.h" #include "scene/theme/theme_db.h" diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp index e266d26b73..f892f3637d 100644 --- a/editor/plugins/tiles/atlas_merging_dialog.cpp +++ b/editor/plugins/tiles/atlas_merging_dialog.cpp @@ -236,7 +236,7 @@ void AtlasMergingDialog::update_tile_set(Ref<TileSet> p_tile_set) { if (atlas_source.is_valid()) { Ref<Texture2D> texture = atlas_source->get_texture(); if (texture.is_valid()) { - String item_text = vformat("%s (id:%d)", texture->get_path().get_file(), source_id); + String item_text = vformat(TTR("%s (ID: %d)"), texture->get_path().get_file(), source_id); atlas_merging_atlases_list->add_item(item_text, texture); atlas_merging_atlases_list->set_item_metadata(-1, source_id); } diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp index c0f6ccb95a..57f9b3135a 100644 --- a/editor/plugins/tiles/tile_data_editors.cpp +++ b/editor/plugins/tiles/tile_data_editors.cpp @@ -38,8 +38,13 @@ #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/menu_button.h" +#include "scene/gui/option_button.h" +#include "scene/gui/separator.h" + #ifdef DEBUG_ENABLED #include "servers/navigation_server_3d.h" #endif // DEBUG_ENABLED @@ -153,7 +158,14 @@ void GenericTilePolygonEditor::_base_control_draw() { // Draw the background. if (background_texture.is_valid()) { - base_control->draw_texture_rect_region(background_texture, Rect2(-background_region.size / 2 - background_offset, background_region.size), background_region, background_modulate, background_transpose); + Size2 region_size = background_region.size; + if (background_h_flip) { + region_size.x = -region_size.x; + } + if (background_v_flip) { + region_size.y = -region_size.y; + } + base_control->draw_texture_rect_region(background_texture, Rect2(-background_region.size / 2 - background_offset, region_size), background_region, background_modulate, background_transpose); } // Draw the polygons. @@ -844,6 +856,7 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() { void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) { ERR_FAIL_COND(!dummy_object); dummy_object->set(p_property, p_value); + emit_signal(SNAME("needs_redraw")); } Variant TileDataDefaultEditor::_get_painted_value() { @@ -1194,8 +1207,6 @@ TileDataDefaultEditor::TileDataDefaultEditor() { label->set_theme_type_variation("HeaderSmall"); add_child(label); - toolbar->add_child(memnew(VSeparator)); - picker_button = memnew(Button); picker_button->set_flat(true); picker_button->set_toggle_mode(true); @@ -1590,12 +1601,31 @@ void TileDataCollisionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transfor } RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform); + + Ref<Texture2D> one_way_icon = get_theme_icon(SNAME("OneWayTile"), SNAME("EditorIcons")); for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) { Vector<Vector2> polygon = tile_data->get_collision_polygon_points(physics_layer, i); - if (polygon.size() >= 3) { - p_canvas_item->draw_polygon(polygon, color); + if (polygon.size() < 3) { + continue; + } + + p_canvas_item->draw_polygon(polygon, color); + + if (tile_data->is_collision_polygon_one_way(physics_layer, i)) { + PackedVector2Array uvs; + uvs.resize(polygon.size()); + Vector2 size_1 = Vector2(1, 1) / tile_set->get_tile_size(); + + for (int j = 0; j < polygon.size(); j++) { + uvs.write[j] = polygon[j] * size_1 + Vector2(0.5, 0.5); + } + + Vector<Color> color2; + color2.push_back(Color(1, 1, 1, 0.4)); + p_canvas_item->draw_polygon(polygon, color2, uvs, one_way_icon); } } + RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), Transform2D()); } @@ -2627,8 +2657,6 @@ TileDataTerrainsEditor::TileDataTerrainsEditor() { add_child(label); // Toolbar - toolbar->add_child(memnew(VSeparator)); - picker_button = memnew(Button); picker_button->set_flat(true); picker_button->set_toggle_mode(true); diff --git a/editor/plugins/tiles/tile_data_editors.h b/editor/plugins/tiles/tile_data_editors.h index 98d337b4cf..e98e1d6701 100644 --- a/editor/plugins/tiles/tile_data_editors.h +++ b/editor/plugins/tiles/tile_data_editors.h @@ -39,6 +39,9 @@ #include "scene/gui/control.h" #include "scene/gui/label.h" +class MenuButton; +class EditorUndoRedoManager; + class TileDataEditor : public VBoxContainer { GDCLASS(TileDataEditor, VBoxContainer); diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index eb7c93872e..4131c06745 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -35,6 +35,7 @@ #include "editor/editor_node.h" #include "editor/editor_resource_preview.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/plugins/canvas_item_editor_plugin.h" @@ -54,7 +55,7 @@ void TileMapEditorTilesPlugin::tile_set_changed() { } void TileMapEditorTilesPlugin::_on_random_tile_checkbox_toggled(bool p_pressed) { - scatter_spinbox->set_editable(p_pressed); + scatter_controls_container->set_visible(p_pressed); } void TileMapEditorTilesPlugin::_on_scattering_spinbox_changed(double p_value) { @@ -155,7 +156,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() { // Common to all type of sources. if (!source->get_name().is_empty()) { - item_text = vformat(TTR("%s (id:%d)"), source->get_name(), source_id); + item_text = vformat(TTR("%s (ID: %d)"), source->get_name(), source_id); } // Atlas source. @@ -164,7 +165,7 @@ void TileMapEditorTilesPlugin::_update_tile_set_sources_list() { texture = atlas_source->get_texture(); if (item_text.is_empty()) { if (texture.is_valid()) { - item_text = vformat("%s (ID: %d)", texture->get_path().get_file(), source_id); + item_text = vformat(TTR("%s (ID: %d)"), texture->get_path().get_file(), source_id); } else { item_text = vformat(TTR("No Texture Atlas Source (ID: %d)"), source_id); } @@ -471,6 +472,7 @@ void TileMapEditorTilesPlugin::_update_theme() { random_tile_toggle->set_icon(tiles_bottom_panel->get_theme_icon(SNAME("RandomNumberGenerator"), SNAME("EditorIcons"))); missing_atlas_texture_icon = tiles_bottom_panel->get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons")); + _update_tile_set_sources_list(); } bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p_event) { @@ -1163,7 +1165,7 @@ HashMap<Vector2i, TileMapCell> TileMapEditorTilesPlugin::_draw_bucket_fill(Vecto } // Get surrounding tiles (handles different tile shapes). - TypedArray<Vector2i> around = tile_map->get_surrounding_tiles(coords); + TypedArray<Vector2i> around = tile_map->get_surrounding_cells(coords); for (int i = 0; i < around.size(); i++) { to_check.push_back(around[i]); } @@ -1696,7 +1698,7 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { if (frame > 0) { color.a *= 0.3; } - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E.get_atlas_coords(), frame), color, false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E.get_atlas_coords(), frame), color); } } } @@ -1704,11 +1706,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { // Draw the hovered tile. if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile == 0 && !tile_set_dragging_selection) { for (int frame = 0; frame < atlas->get_tile_animation_frames_count(hovered_tile.get_atlas_coords()); frame++) { - Color color = Color(1.0, 1.0, 1.0); - if (frame > 0) { - color.a *= 0.3; - } - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color, false); + Color color = Color(1.0, 0.8, 0.0, frame == 0 ? 0.6 : 0.3); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(hovered_tile.get_atlas_coords(), frame), color); } } @@ -1729,9 +1728,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() { } } } - Color selection_rect_color = selection_color.lightened(0.2); for (const Vector2i &E : to_draw) { - tile_atlas_control->draw_rect(atlas->get_tile_texture_region(E), selection_rect_color, false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, atlas->get_tile_texture_region(E)); } } } @@ -1880,7 +1878,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() { if (E.source_id == source_id && E.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && E.alternative_tile > 0) { Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E.get_atlas_coords(), E.alternative_tile); if (rect != Rect2i()) { - alternative_tiles_control->draw_rect(rect, Color(0.2, 0.2, 1.0), false); + TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect); } } } @@ -1889,7 +1887,7 @@ void TileMapEditorTilesPlugin::_tile_alternatives_control_draw() { if (hovered_tile.get_atlas_coords() != TileSetSource::INVALID_ATLAS_COORDS && hovered_tile.alternative_tile > 0) { Rect2i rect = tile_atlas_view->get_alternative_tile_rect(hovered_tile.get_atlas_coords(), hovered_tile.alternative_tile); if (rect != Rect2i()) { - alternative_tiles_control->draw_rect(rect, Color(1.0, 1.0, 1.0), false); + TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect, Color(1.0, 0.8, 0.0, 0.5)); } } } @@ -2126,10 +2124,12 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { tools_settings->add_child(random_tile_toggle); // Random tile scattering. + scatter_controls_container = memnew(HBoxContainer); + scatter_label = memnew(Label); scatter_label->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile.")); scatter_label->set_text(TTR("Scattering:")); - tools_settings->add_child(scatter_label); + scatter_controls_container->add_child(scatter_label); scatter_spinbox = memnew(SpinBox); scatter_spinbox->set_min(0.0); @@ -2138,7 +2138,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() { scatter_spinbox->set_tooltip_text(TTR("Defines the probability of painting nothing instead of a randomly selected tile.")); scatter_spinbox->get_line_edit()->add_theme_constant_override("minimum_character_width", 4); scatter_spinbox->connect("value_changed", callable_mp(this, &TileMapEditorTilesPlugin::_on_scattering_spinbox_changed)); - tools_settings->add_child(scatter_spinbox); + scatter_controls_container->add_child(scatter_spinbox); + tools_settings->add_child(scatter_controls_container); _on_random_tile_checkbox_toggled(false); @@ -2546,7 +2547,7 @@ RBSet<Vector2i> TileMapEditorTerrainsPlugin::_get_cells_for_bucket_fill(Vector2i output.insert(coords); // Get surrounding tiles (handles different tile shapes). - TypedArray<Vector2i> around = tile_map->get_surrounding_tiles(coords); + TypedArray<Vector2i> around = tile_map->get_surrounding_cells(coords); for (int i = 0; i < around.size(); i++) { to_check.push_back(around[i]); } diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h index ad27795437..9700e26e01 100644 --- a/editor/plugins/tiles/tile_map_editor.h +++ b/editor/plugins/tiles/tile_map_editor.h @@ -91,6 +91,8 @@ private: VSeparator *tools_settings_vsep_2 = nullptr; CheckBox *bucket_contiguous_checkbox = nullptr; Button *random_tile_toggle = nullptr; + + HBoxContainer *scatter_controls_container = nullptr; float scattering = 0.0; Label *scatter_label = nullptr; SpinBox *scatter_spinbox = nullptr; diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp index 50350de97e..b31fb1aa58 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp @@ -32,9 +32,11 @@ #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "scene/gui/separator.h" -void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index) { +void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index, Object *p_item_list) { if (p_mouse_button_index != MouseButton::RIGHT) { return; } @@ -75,7 +77,7 @@ void TileProxiesManagerDialog::_delete_selected_bindings() { Vector<int> alternative_level_selected = alternative_level_list->get_selected_items(); for (int i = 0; i < alternative_level_selected.size(); i++) { Array key = alternative_level_list->get_item_metadata(alternative_level_selected[i]); - Array val = tile_set->get_coords_level_tile_proxy(key[0], key[1]); + Array val = tile_set->get_alternative_level_tile_proxy(key[0], key[1], key[2]); undo_redo->add_do_method(*tile_set, "remove_alternative_level_tile_proxy", key[0], key[1], key[2]); undo_redo->add_undo_method(*tile_set, "set_alternative_level_tile_proxy", key[0], key[1], key[2], val[0], val[1], val[2]); } diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.h b/editor/plugins/tiles/tile_proxies_manager_dialog.h index d0f1933882..09c8068336 100644 --- a/editor/plugins/tiles/tile_proxies_manager_dialog.h +++ b/editor/plugins/tiles/tile_proxies_manager_dialog.h @@ -36,6 +36,8 @@ #include "scene/gui/dialogs.h" #include "scene/gui/item_list.h" +class EditorUndoRedoManager; + class TileProxiesManagerDialog : public ConfirmationDialog { GDCLASS(TileProxiesManagerDialog, ConfirmationDialog); @@ -59,7 +61,7 @@ private: EditorPropertyInteger *alternative_to_property_editor = nullptr; PopupMenu *popup_menu = nullptr; - void _right_clicked(int p_item, Vector2 p_local_mouse_pos, Object *p_item_list, MouseButton p_mouse_button_index); + void _right_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index, Object *p_item_list); void _menu_id_pressed(int p_id); void _delete_selected_bindings(); void _update_lists(); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp index 8e69abd7ff..34bbfa2c7e 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp @@ -35,10 +35,10 @@ #include "editor/editor_inspector.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/progress_dialog.h" -#include "editor/editor_node.h" #include "scene/gui/box_container.h" #include "scene/gui/button.h" #include "scene/gui/control.h" @@ -64,11 +64,15 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id(int p_id) { emit_signal(SNAME("changed"), "id"); } -int TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id() { +int TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id() const { return source_id; } bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_set(const StringName &p_name, const Variant &p_value) { + if (p_name == "id") { + set_id(p_value); + return true; + } String name = p_name; if (name == "name") { // Use the resource_name property to store the source's name. @@ -86,6 +90,10 @@ bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get(const StringN if (!tile_set_atlas_source) { return false; } + if (p_name == "id") { + r_ret = get_id(); + return true; + } String name = p_name; if (name == "name") { // Use the resource_name property to store the source's name. @@ -97,6 +105,8 @@ bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get(const StringN } void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list(List<PropertyInfo> *p_list) const { + p_list->push_back(PropertyInfo(Variant::NIL, TTR("Atlas"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); + p_list->push_back(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0," + itos(INT_MAX) + ",1")); p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, "")); p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D")); p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px")); @@ -106,12 +116,6 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list } void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() { - // -- Shape and layout -- - ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id); - ClassDB::bind_method(D_METHOD("get_id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id); - - ADD_PROPERTY(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0," + itos(INT_MAX) + ",1"), "set_id", "get_id"); - ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what"))); } @@ -152,7 +156,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na // ID and size related properties. if (tiles.size() == 1) { - const Vector2i &coords = tiles.front()->get().tile; + const Vector2i coords = tiles.front()->get().tile; const int &alternative = tiles.front()->get().alternative; if (alternative == 0) { @@ -383,11 +387,15 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro // ID and size related properties. if (tiles.size() == 1) { if (tiles.front()->get().alternative == 0) { - p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords", PROPERTY_HINT_NONE, "")); - p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::NIL, TTR("Base Tile"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords")); + p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas")); } else { - p_list->push_back(PropertyInfo(Variant::INT, "alternative_id", PROPERTY_HINT_NONE, "")); + p_list->push_back(PropertyInfo(Variant::NIL, TTR("Alternative Tile"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); + p_list->push_back(PropertyInfo(Variant::INT, "alternative_id")); } + } else { + p_list->push_back(PropertyInfo(Variant::NIL, TTR("Tiles"), PROPERTY_HINT_NONE, String(), PROPERTY_USAGE_CATEGORY)); } // Animation. @@ -443,6 +451,11 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro HashMap<String, int> counts; // Counts the number of time a property appears (useful for groups that may appear more than once) for (List<PropertyInfo>::Element *E_property = list.front(); E_property; E_property = E_property->next()) { + // Don't show category for TileData. + if (E_property->get().usage & PROPERTY_USAGE_CATEGORY) { + continue; + } + const String &property_string = E_property->get().name; if (!tile_data->is_allowing_transform() && (property_string == "flip_h" || property_string == "flip_v" || property_string == "transpose")) { continue; @@ -543,11 +556,13 @@ void TileSetAtlasSourceEditor::_update_source_inspector() { void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() { // Fix selected. - for (RBSet<TileSelection>::Element *E = selection.front(); E; E = E->next()) { + for (RBSet<TileSelection>::Element *E = selection.front(); E;) { + RBSet<TileSelection>::Element *N = E->next(); TileSelection selected = E->get(); if (!tile_set_atlas_source->has_tile(selected.tile) || !tile_set_atlas_source->has_alternative_tile(selected.tile, selected.alternative)) { selection.erase(E); } + E = N; } // Fix hovered. @@ -564,7 +579,6 @@ void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() { void TileSetAtlasSourceEditor::_update_atlas_source_inspector() { // Update visibility. bool inspector_visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button; - atlas_source_inspector_label->set_visible(inspector_visible); atlas_source_inspector->set_visible(inspector_visible); } @@ -574,11 +588,9 @@ void TileSetAtlasSourceEditor::_update_tile_inspector() { if (!selection.is_empty()) { tile_proxy_object->edit(tile_set_atlas_source, selection); } - tile_inspector_label->show(); tile_inspector->set_visible(!selection.is_empty()); tile_inspector_no_tile_selected_label->set_visible(selection.is_empty()); } else { - tile_inspector_label->hide(); tile_inspector->hide(); tile_inspector_no_tile_selected_label->hide(); } @@ -795,7 +807,7 @@ void TileSetAtlasSourceEditor::_update_tile_data_editors() { } else { tile_data_editor_dropdown_button->set_text(TTR("Select a property editor")); } - tile_data_editors_label->set_visible(is_visible); + tile_data_editors_scroll->set_visible(is_visible); } void TileSetAtlasSourceEditor::_update_current_tile_data_editor() { @@ -952,21 +964,18 @@ void TileSetAtlasSourceEditor::_update_toolbar() { if (current_tile_data_editor_toolbar) { current_tile_data_editor_toolbar->hide(); } - tool_settings_vsep->show(); tools_settings_erase_button->show(); tool_advanced_menu_buttom->show(); } else if (tools_button_group->get_pressed_button() == tool_select_button) { if (current_tile_data_editor_toolbar) { current_tile_data_editor_toolbar->hide(); } - tool_settings_vsep->hide(); tools_settings_erase_button->hide(); tool_advanced_menu_buttom->hide(); } else if (tools_button_group->get_pressed_button() == tool_paint_button) { if (current_tile_data_editor_toolbar) { current_tile_data_editor_toolbar->show(); } - tool_settings_vsep->hide(); tools_settings_erase_button->hide(); tool_advanced_menu_buttom->hide(); } @@ -1682,10 +1691,6 @@ Array TileSetAtlasSourceEditor::_get_selection_as_array() { } void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { - // Colors. - Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color"); - Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); - // Draw the selected tile. if (tools_button_group->get_pressed_button() == tool_select_button) { for (const TileSelection &E : selection) { @@ -1693,12 +1698,9 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { if (selected.alternative == 0) { // Draw the rect. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(selected.tile); frame++) { - Color color = selection_color; - if (frame > 0) { - color.a *= 0.3; - } + Color color = Color(0.0, 1.0, 0.0, frame == 0 ? 1.0 : 0.3); Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile, frame); - tile_atlas_control->draw_rect(region, color, false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, region, color); } } } @@ -1740,7 +1742,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { // Draw the tiles to be removed. for (const Vector2i &E : drag_modified_tiles) { for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(E); frame++) { - tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E, frame), Color(0.0, 0.0, 0.0), false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(E, frame), Color(0.0, 0.0, 0.0)); } } } else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) { @@ -1752,7 +1754,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Color color = Color(0.0, 0.0, 0.0); if (drag_type == DRAG_TYPE_RECT_SELECT) { - color = selection_color.lightened(0.2); + color = Color(1.0, 1.0, 0.0); } RBSet<Vector2i> to_paint; @@ -1767,7 +1769,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { for (const Vector2i &E : to_paint) { Vector2i coords = E; - tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(coords), color, false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(coords), color); } } else if (drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) { // Draw tiles to be created. @@ -1784,7 +1786,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Vector2i coords = Vector2i(x, y); if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) { Vector2i origin = margins + (coords * (tile_size + separation)); - tile_atlas_control->draw_rect(Rect2i(origin, tile_size), Color(1.0, 1.0, 1.0), false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, Rect2i(origin, tile_size)); } } } @@ -1801,7 +1803,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Vector2i separation = tile_set_atlas_source->get_separation(); Vector2i tile_size = tile_set_atlas_source->get_texture_region_size(); Vector2i origin = margins + (area.position * (tile_size + separation)); - tile_atlas_control->draw_rect(Rect2i(origin, area.size * tile_size), Color(1.0, 1.0, 1.0), false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, Rect2i(origin, area.size * tile_size)); } else { Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size(); if (hovered_base_tile_coords.x >= 0 && hovered_base_tile_coords.y >= 0 && hovered_base_tile_coords.x < grid_size.x && hovered_base_tile_coords.y < grid_size.y) { @@ -1809,11 +1811,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { if (hovered_tile != TileSetSource::INVALID_ATLAS_COORDS) { // Draw existing hovered tile. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(hovered_tile); frame++) { - Color color = Color(1.0, 1.0, 1.0); - if (frame > 0) { - color.a *= 0.3; - } - tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color, false); + Color color = Color(1.0, 0.8, 0.0, frame == 0 ? 0.6 : 0.3); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color); } } else { // Draw empty tile, only in add/remove tiles mode. @@ -1822,7 +1821,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() { Vector2i separation = tile_set_atlas_source->get_separation(); Vector2i tile_size = tile_set_atlas_source->get_texture_region_size(); Vector2i origin = margins + (hovered_base_tile_coords * (tile_size + separation)); - tile_atlas_control->draw_rect(Rect2i(origin, tile_size), Color(1.0, 1.0, 1.0), false); + TilesEditorPlugin::draw_selection_rect(tile_atlas_control, Rect2i(origin, tile_size)); } } } @@ -1974,9 +1973,6 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() { } void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { - Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color"); - Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0); - // Update the hovered alternative tile. if (tools_button_group->get_pressed_button() == tool_select_button) { // Draw hovered tile. @@ -1984,7 +1980,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { if (coords != TileSetSource::INVALID_ATLAS_COORDS) { Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, hovered_alternative_tile_coords.z); if (rect != Rect2i()) { - alternative_tiles_control->draw_rect(rect, Color(1.0, 1.0, 1.0), false); + TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect, Color(1.0, 0.8, 0.0, 0.5)); } } @@ -1994,7 +1990,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() { if (selected.alternative >= 1) { Rect2i rect = tile_atlas_view->get_alternative_tile_rect(selected.tile, selected.alternative); if (rect != Rect2i()) { - alternative_tiles_control->draw_rect(rect, selection_color, false); + TilesEditorPlugin::draw_selection_rect(alternative_tiles_control, rect); } } } @@ -2343,6 +2339,15 @@ void TileSetAtlasSourceEditor::_notification(int p_what) { tile_set_changed_needs_update = false; } } break; + + case NOTIFICATION_EXIT_TREE: { + for (KeyValue<String, TileDataEditor *> &E : tile_data_editors) { + Control *toolbar = E.value->get_toolbar(); + if (toolbar->get_parent() == tool_settings_tile_data_toolbar_container) { + tool_settings_tile_data_toolbar_container->remove_child(toolbar); + } + } + } break; } } @@ -2357,54 +2362,90 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { set_process_unhandled_key_input(true); set_process_internal(true); - // -- Right side -- - HSplitContainer *split_container_right_side = memnew(HSplitContainer); - split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL); - add_child(split_container_right_side); - // Middle panel. - ScrollContainer *middle_panel = memnew(ScrollContainer); - middle_panel->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); - middle_panel->set_custom_minimum_size(Size2(200, 0) * EDSCALE); - split_container_right_side->add_child(middle_panel); - VBoxContainer *middle_vbox_container = memnew(VBoxContainer); - middle_vbox_container->set_h_size_flags(SIZE_EXPAND_FILL); - middle_panel->add_child(middle_vbox_container); + middle_vbox_container->set_custom_minimum_size(Size2(200, 0) * EDSCALE); + add_child(middle_vbox_container); - // Tile inspector. - tile_inspector_label = memnew(Label); - tile_inspector_label->set_text(TTR("Tile Properties:")); - tile_inspector_label->set_theme_type_variation("HeaderSmall"); - middle_vbox_container->add_child(tile_inspector_label); + // -- Toolbox -- + tools_button_group.instantiate(); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_source_inspector).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_data_editors).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_current_tile_data_editor).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1)); + tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar).unbind(1)); + HBoxContainer *toolbox = memnew(HBoxContainer); + middle_vbox_container->add_child(toolbox); + + tool_setup_atlas_source_button = memnew(Button); + tool_setup_atlas_source_button->set_text(TTR("Setup")); + tool_setup_atlas_source_button->set_flat(true); + tool_setup_atlas_source_button->set_toggle_mode(true); + tool_setup_atlas_source_button->set_pressed(true); + tool_setup_atlas_source_button->set_button_group(tools_button_group); + tool_setup_atlas_source_button->set_tooltip_text(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing).")); + toolbox->add_child(tool_setup_atlas_source_button); + + tool_select_button = memnew(Button); + tool_select_button->set_text(TTR("Select")); + tool_select_button->set_flat(true); + tool_select_button->set_toggle_mode(true); + tool_select_button->set_pressed(false); + tool_select_button->set_button_group(tools_button_group); + tool_select_button->set_tooltip_text(TTR("Select tiles.")); + toolbox->add_child(tool_select_button); + + tool_paint_button = memnew(Button); + tool_paint_button->set_text(TTR("Paint")); + tool_paint_button->set_flat(true); + tool_paint_button->set_toggle_mode(true); + tool_paint_button->set_button_group(tools_button_group); + tool_paint_button->set_tooltip_text(TTR("Paint properties.")); + toolbox->add_child(tool_paint_button); + + // Tile inspector. tile_proxy_object = memnew(AtlasTileProxyObject(this)); tile_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_proxy_object_changed)); tile_inspector = memnew(EditorInspector); - tile_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + tile_inspector->set_v_size_flags(SIZE_EXPAND_FILL); + tile_inspector->set_show_categories(true); tile_inspector->edit(tile_proxy_object); tile_inspector->set_use_folding(true); tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected)); middle_vbox_container->add_child(tile_inspector); tile_inspector_no_tile_selected_label = memnew(Label); + tile_inspector_no_tile_selected_label->set_v_size_flags(SIZE_EXPAND | SIZE_SHRINK_CENTER); tile_inspector_no_tile_selected_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); tile_inspector_no_tile_selected_label->set_text(TTR("No tiles selected.")); middle_vbox_container->add_child(tile_inspector_no_tile_selected_label); // Property values palette. + tile_data_editors_scroll = memnew(ScrollContainer); + tile_data_editors_scroll->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + tile_data_editors_scroll->set_v_size_flags(SIZE_EXPAND_FILL); + middle_vbox_container->add_child(tile_data_editors_scroll); + + VBoxContainer *tile_data_editors_vbox = memnew(VBoxContainer); + tile_data_editors_vbox->set_h_size_flags(SIZE_EXPAND_FILL); + tile_data_editors_scroll->add_child(tile_data_editors_vbox); + tile_data_editors_popup = memnew(Popup); tile_data_editors_label = memnew(Label); tile_data_editors_label->set_text(TTR("Paint Properties:")); tile_data_editors_label->set_theme_type_variation("HeaderSmall"); - middle_vbox_container->add_child(tile_data_editors_label); + tile_data_editors_vbox->add_child(tile_data_editors_label); tile_data_editor_dropdown_button = memnew(Button); tile_data_editor_dropdown_button->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw)); tile_data_editor_dropdown_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed)); - middle_vbox_container->add_child(tile_data_editor_dropdown_button); + tile_data_editors_vbox->add_child(tile_data_editor_dropdown_button); tile_data_editor_dropdown_button->add_child(tile_data_editors_popup); tile_data_editors_tree = memnew(Tree); @@ -2417,80 +2458,25 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_data_painting_editor_container = memnew(VBoxContainer); tile_data_painting_editor_container->set_h_size_flags(SIZE_EXPAND_FILL); - middle_vbox_container->add_child(tile_data_painting_editor_container); + tile_data_editors_vbox->add_child(tile_data_painting_editor_container); // Atlas source inspector. - atlas_source_inspector_label = memnew(Label); - atlas_source_inspector_label->set_text(TTR("Atlas Properties:")); - atlas_source_inspector_label->set_theme_type_variation("HeaderSmall"); - middle_vbox_container->add_child(atlas_source_inspector_label); - atlas_source_proxy_object = memnew(TileSetAtlasSourceProxyObject()); atlas_source_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed)); atlas_source_inspector = memnew(EditorInspector); - atlas_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED); + atlas_source_inspector->set_v_size_flags(SIZE_EXPAND_FILL); + atlas_source_inspector->set_show_categories(true); atlas_source_inspector->edit(atlas_source_proxy_object); middle_vbox_container->add_child(atlas_source_inspector); - // Right panel. - VBoxContainer *right_panel = memnew(VBoxContainer); - right_panel->set_h_size_flags(SIZE_EXPAND_FILL); - right_panel->set_v_size_flags(SIZE_EXPAND_FILL); - split_container_right_side->add_child(right_panel); - - // -- Dialogs -- - confirm_auto_create_tiles = memnew(AcceptDialog); - confirm_auto_create_tiles->set_title(TTR("Auto Create Tiles in Non-Transparent Texture Regions?")); - confirm_auto_create_tiles->set_text(TTR("The atlas's texture was modified.\nWould you like to automatically create tiles in the atlas?")); - confirm_auto_create_tiles->set_ok_button_text(TTR("Yes")); - confirm_auto_create_tiles->add_cancel_button()->set_text(TTR("No")); - confirm_auto_create_tiles->connect("confirmed", callable_mp(this, &TileSetAtlasSourceEditor::_auto_create_tiles)); - add_child(confirm_auto_create_tiles); - - // -- Toolbox -- - tools_button_group.instantiate(); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_source_inspector).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_data_editors).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_current_tile_data_editor).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1)); - tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar).unbind(1)); - - toolbox = memnew(HBoxContainer); - right_panel->add_child(toolbox); - - tool_setup_atlas_source_button = memnew(Button); - tool_setup_atlas_source_button->set_flat(true); - tool_setup_atlas_source_button->set_toggle_mode(true); - tool_setup_atlas_source_button->set_pressed(true); - tool_setup_atlas_source_button->set_button_group(tools_button_group); - tool_setup_atlas_source_button->set_tooltip_text(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing).")); - toolbox->add_child(tool_setup_atlas_source_button); - - tool_select_button = memnew(Button); - tool_select_button->set_flat(true); - tool_select_button->set_toggle_mode(true); - tool_select_button->set_pressed(false); - tool_select_button->set_button_group(tools_button_group); - tool_select_button->set_tooltip_text(TTR("Select tiles.")); - toolbox->add_child(tool_select_button); - - tool_paint_button = memnew(Button); - tool_paint_button->set_flat(true); - tool_paint_button->set_toggle_mode(true); - tool_paint_button->set_button_group(tools_button_group); - tool_paint_button->set_tooltip_text(TTR("Paint properties.")); - toolbox->add_child(tool_paint_button); + // -- Right side -- + VBoxContainer *right_vbox_container = memnew(VBoxContainer); + add_child(right_vbox_container); // Tool settings. tool_settings = memnew(HBoxContainer); - toolbox->add_child(tool_settings); - - tool_settings_vsep = memnew(VSeparator); - tool_settings->add_child(tool_settings_vsep); + right_vbox_container->add_child(tool_settings); tool_settings_tile_data_toolbar_container = memnew(HBoxContainer); tool_settings->add_child(tool_settings_tile_data_toolbar_container); @@ -2507,24 +2493,31 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES); tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES); tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option)); - toolbox->add_child(tool_advanced_menu_buttom); + tool_settings->add_child(tool_advanced_menu_buttom); _update_toolbar(); // Right side of toolbar. Control *middle_space = memnew(Control); middle_space->set_h_size_flags(SIZE_EXPAND_FILL); - toolbox->add_child(middle_space); + tool_settings->add_child(middle_space); tool_tile_id_label = memnew(Label); tool_tile_id_label->set_mouse_filter(Control::MOUSE_FILTER_STOP); - toolbox->add_child(tool_tile_id_label); + tool_settings->add_child(tool_tile_id_label); _update_tile_id_label(); + // Right panel. + VBoxContainer *right_panel = memnew(VBoxContainer); + right_panel->set_h_size_flags(SIZE_EXPAND_FILL); + right_panel->set_v_size_flags(SIZE_EXPAND_FILL); + right_vbox_container->add_child(right_panel); + // Tile atlas view. tile_atlas_view = memnew(TileAtlasView); tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL); tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL); + tile_atlas_view->set_custom_minimum_size(Size2(200, 0) * EDSCALE); tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_atlas_view_transform)); tile_atlas_view->connect("transform_changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed).unbind(2)); right_panel->add_child(tile_atlas_view); @@ -2567,17 +2560,17 @@ TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() { tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false); alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE); - tile_atlas_view_missing_source_label = memnew(Label); - tile_atlas_view_missing_source_label->set_text(TTR("Add or select an atlas texture to the left panel.")); - tile_atlas_view_missing_source_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER); - tile_atlas_view_missing_source_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER); - tile_atlas_view_missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL); - tile_atlas_view_missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL); - tile_atlas_view_missing_source_label->hide(); - right_panel->add_child(tile_atlas_view_missing_source_label); - EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetAtlasSourceEditor::_undo_redo_inspector_callback)); + // -- Dialogs -- + confirm_auto_create_tiles = memnew(AcceptDialog); + confirm_auto_create_tiles->set_title(TTR("Auto Create Tiles in Non-Transparent Texture Regions?")); + confirm_auto_create_tiles->set_text(TTR("The atlas's texture was modified.\nWould you like to automatically create tiles in the atlas?")); + confirm_auto_create_tiles->set_ok_button_text(TTR("Yes")); + confirm_auto_create_tiles->add_cancel_button()->set_text(TTR("No")); + confirm_auto_create_tiles->connect("confirmed", callable_mp(this, &TileSetAtlasSourceEditor::_auto_create_tiles)); + add_child(confirm_auto_create_tiles); + // Inspector plugin. Ref<EditorInspectorPluginTileData> tile_data_inspector_plugin; tile_data_inspector_plugin.instantiate(); diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h index 8e217e359f..eede2ec086 100644 --- a/editor/plugins/tiles/tile_set_atlas_source_editor.h +++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h @@ -37,10 +37,13 @@ #include "scene/gui/split_container.h" #include "scene/resources/tile_set.h" +class Popup; class TileSet; +class Tree; +class VSeparator; -class TileSetAtlasSourceEditor : public HBoxContainer { - GDCLASS(TileSetAtlasSourceEditor, HBoxContainer); +class TileSetAtlasSourceEditor : public HSplitContainer { + GDCLASS(TileSetAtlasSourceEditor, HSplitContainer); public: // A class to store which tiles are selected. @@ -74,7 +77,7 @@ public: public: void set_id(int p_id); - int get_id(); + int get_id() const; void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id); TileSetAtlasSource *get_edited() { return tile_set_atlas_source; }; @@ -117,6 +120,7 @@ private: bool tile_set_changed_needs_update = false; // -- Properties painting -- + ScrollContainer *tile_data_editors_scroll = nullptr; VBoxContainer *tile_data_painting_editor_container = nullptr; Label *tile_data_editors_label = nullptr; Button *tile_data_editor_dropdown_button = nullptr; @@ -134,19 +138,15 @@ private: // -- Inspector -- AtlasTileProxyObject *tile_proxy_object = nullptr; - Label *tile_inspector_label = nullptr; EditorInspector *tile_inspector = nullptr; Label *tile_inspector_no_tile_selected_label = nullptr; String selected_property; void _inspector_property_selected(String p_property); TileSetAtlasSourceProxyObject *atlas_source_proxy_object = nullptr; - Label *atlas_source_inspector_label = nullptr; EditorInspector *atlas_source_inspector = nullptr; // -- Atlas view -- - HBoxContainer *toolbox = nullptr; - Label *tile_atlas_view_missing_source_label = nullptr; TileAtlasView *tile_atlas_view = nullptr; // Dragging @@ -207,7 +207,6 @@ private: // Tool settings. HBoxContainer *tool_settings = nullptr; - VSeparator *tool_settings_vsep = nullptr; HBoxContainer *tool_settings_tile_data_toolbar_container = nullptr; Button *tools_settings_erase_button = nullptr; MenuButton *tool_advanced_menu_buttom = nullptr; diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp index dccff80512..e8ceacf8f8 100644 --- a/editor/plugins/tiles/tile_set_editor.cpp +++ b/editor/plugins/tiles/tile_set_editor.cpp @@ -36,6 +36,7 @@ #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/gui/box_container.h" @@ -119,7 +120,9 @@ bool TileSetEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_da } void TileSetEditor::_update_sources_list(int force_selected_id) { - ERR_FAIL_COND(!tile_set.is_valid()); + if (tile_set.is_null()) { + return; + } // Get the previously selected id. int old_selected = TileSet::INVALID_SOURCE; @@ -150,7 +153,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) { // Common to all type of sources. if (!source->get_name().is_empty()) { - item_text = vformat(TTR("%s (id:%d)"), source->get_name(), source_id); + item_text = vformat(TTR("%s (ID: %d)"), source->get_name(), source_id); } // Atlas source. @@ -159,7 +162,7 @@ void TileSetEditor::_update_sources_list(int force_selected_id) { texture = atlas_source->get_texture(); if (item_text.is_empty()) { if (texture.is_valid()) { - item_text = vformat("%s (ID: %d)", texture->get_path().get_file(), source_id); + item_text = vformat(TTR("%s (ID: %d)"), texture->get_path().get_file(), source_id); } else { item_text = vformat(TTR("No Texture Atlas Source (ID: %d)"), source_id); } @@ -345,6 +348,7 @@ void TileSetEditor::_notification(int p_what) { source_sort_button->set_icon(get_theme_icon(SNAME("Sort"), SNAME("EditorIcons"))); sources_advanced_menu_button->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons"))); missing_texture_texture = get_theme_icon(SNAME("TileSet"), SNAME("EditorIcons")); + _update_sources_list(); } break; case NOTIFICATION_INTERNAL_PROCESS: { diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp index 3b711a568e..a14aad6652 100644 --- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp +++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp @@ -38,6 +38,7 @@ #include "editor/editor_undo_redo_manager.h" #include "scene/gui/item_list.h" +#include "scene/gui/split_container.h" #include "core/core_string_names.h" diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp index 4239e2c981..ee29913334 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.cpp +++ b/editor/plugins/tiles/tiles_editor_plugin.cpp @@ -30,10 +30,13 @@ #include "tiles_editor_plugin.h" +#include "tile_set_editor.h" + #include "core/os/mutex.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "scene/2d/tile_map.h" @@ -43,8 +46,6 @@ #include "scene/gui/separator.h" #include "scene/resources/tile_set.h" -#include "tile_set_editor.h" - TilesEditorPlugin *TilesEditorPlugin::singleton = nullptr; void TilesEditorPlugin::_preview_frame_started() { @@ -384,6 +385,15 @@ bool TilesEditorPlugin::handles(Object *p_object) const { return p_object->is_class("TileMap") || p_object->is_class("TileSet"); } +void TilesEditorPlugin::draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color) { + real_t scale = p_ci->get_global_transform().get_scale().x * 0.5; + p_ci->draw_set_transform(p_rect.position, 0, Vector2(1, 1) / scale); + RS::get_singleton()->canvas_item_add_nine_patch( + p_ci->get_canvas_item(), Rect2(Vector2(), p_rect.size * scale), Rect2(), EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("TileSelection"), SNAME("EditorIcons"))->get_rid(), + Vector2(2, 2), Vector2(2, 2), RS::NINE_PATCH_STRETCH, RS::NINE_PATCH_STRETCH, false, p_color); + p_ci->draw_set_transform_matrix(Transform2D()); +} + TilesEditorPlugin::TilesEditorPlugin() { set_process_internal(true); diff --git a/editor/plugins/tiles/tiles_editor_plugin.h b/editor/plugins/tiles/tiles_editor_plugin.h index fe0d8179bc..825a10dac2 100644 --- a/editor/plugins/tiles/tiles_editor_plugin.h +++ b/editor/plugins/tiles/tiles_editor_plugin.h @@ -128,6 +128,8 @@ public: virtual bool handles(Object *p_object) const override; virtual void make_visible(bool p_visible) override; + static void draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color = Color(1.0, 1.0, 1.0)); + TilesEditorPlugin(); ~TilesEditorPlugin(); }; diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp index 4fdfaed50e..369a59c443 100644 --- a/editor/plugins/version_control_editor_plugin.cpp +++ b/editor/plugins/version_control_editor_plugin.cpp @@ -38,6 +38,7 @@ #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/filesystem_dock.h" +#include "editor/plugins/script_editor_plugin.h" #include "scene/gui/separator.h" #define CHECK_PLUGIN_INITIALIZED() \ @@ -987,7 +988,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { metadata_dialog->set_title(TTR("Create Version Control Metadata")); metadata_dialog->set_min_size(Size2(200, 40)); metadata_dialog->get_ok_button()->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_create_vcs_metadata_files)); - version_control_actions->add_child(metadata_dialog); + add_child(metadata_dialog); VBoxContainer *metadata_vb = memnew(VBoxContainer); metadata_dialog->add_child(metadata_vb); @@ -1016,7 +1017,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() { set_up_dialog->set_min_size(Size2(600, 100)); set_up_dialog->add_cancel_button("Cancel"); set_up_dialog->set_hide_on_ok(true); - version_control_actions->add_child(set_up_dialog); + add_child(set_up_dialog); Button *set_up_apply_button = set_up_dialog->get_ok_button(); set_up_apply_button->set_text(TTR("Apply")); diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index a51396d712..cf811067c9 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -32,31 +32,31 @@ #include "core/config/project_settings.h" #include "core/core_string_names.h" -#include "core/input/input.h" #include "core/io/resource_loader.h" #include "core/math/math_defs.h" #include "core/os/keyboard.h" -#include "editor/editor_log.h" #include "editor/editor_node.h" #include "editor/editor_properties.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/plugins/curve_editor_plugin.h" #include "editor/plugins/shader_editor_plugin.h" -#include "scene/animation/animation_player.h" #include "scene/gui/button.h" +#include "scene/gui/check_box.h" #include "scene/gui/code_edit.h" #include "scene/gui/graph_edit.h" #include "scene/gui/menu_button.h" -#include "scene/gui/panel.h" +#include "scene/gui/option_button.h" #include "scene/gui/popup.h" #include "scene/gui/rich_text_label.h" +#include "scene/gui/separator.h" #include "scene/gui/tree.h" #include "scene/gui/view_panner.h" #include "scene/main/window.h" #include "scene/resources/visual_shader_nodes.h" #include "scene/resources/visual_shader_particle_nodes.h" -#include "scene/resources/visual_shader_sdf_nodes.h" #include "servers/display_server.h" #include "servers/rendering/shader_types.h" @@ -269,6 +269,19 @@ void VisualShaderGraphPlugin::set_expression(VisualShader::Type p_type, int p_no links[p_node_id].expression_edit->set_text(p_expression); } +Ref<Script> VisualShaderGraphPlugin::get_node_script(int p_node_id) const { + if (!links.has(p_node_id)) { + return Ref<Script>(); + } + + Ref<VisualShaderNodeCustom> custom = Ref<VisualShaderNodeCustom>(links[p_node_id].visual_node); + if (custom.is_valid()) { + return custom->get_script(); + } + + return Ref<Script>(); +} + void VisualShaderGraphPlugin::update_node_size(int p_node_id) { if (!links.has(p_node_id)) { return; @@ -1137,10 +1150,6 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } -void VisualShaderEditor::update_nodes() { - _update_nodes(); -} - void VisualShaderEditor::add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin) { if (plugins.has(p_plugin)) { return; @@ -1202,6 +1211,228 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> add_options.push_back(ao); } +Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) { + Dictionary dict; + dict["script"] = p_custom_node->get_script(); + + String name; + if (p_custom_node->has_method("_get_name")) { + name = (String)p_custom_node->call("_get_name"); + } else { + name = "Unnamed"; + } + dict["name"] = name; + + String description = ""; + if (p_custom_node->has_method("_get_description")) { + description = (String)p_custom_node->call("_get_description"); + } + dict["description"] = description; + + int return_icon_type = -1; + if (p_custom_node->has_method("_get_return_icon_type")) { + return_icon_type = (int)p_custom_node->call("_get_return_icon_type"); + } + dict["return_icon_type"] = return_icon_type; + + String category = ""; + if (p_custom_node->has_method("_get_category")) { + category = (String)p_custom_node->call("_get_category"); + } + category = category.rstrip("/"); + category = category.lstrip("/"); + category = "Addons/" + category; + + String subcategory = ""; + if (p_custom_node->has_method("_get_subcategory")) { + subcategory = (String)p_custom_node->call("_get_subcategory"); + } + if (!subcategory.is_empty()) { + category += "/" + subcategory; + } + dict["category"] = category; + + bool highend = false; + if (p_custom_node->has_method("_is_highend")) { + highend = (bool)p_custom_node->call("_is_highend"); + } + dict["highend"] = highend; + + return dict; +} + +void VisualShaderEditor::update_custom_type(const Ref<Resource> &p_resource) { + Ref<Script> scr = Ref<Script>(p_resource.ptr()); + if (scr.is_null() || scr->get_instance_base_type() != String("VisualShaderNodeCustom")) { + return; + } + + Ref<VisualShaderNodeCustom> ref; + ref.instantiate(); + ref->set_script(scr); + if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { + for (int i = 0; i < add_options.size(); i++) { + if (add_options[i].is_custom && add_options[i].script == scr) { + add_options.remove_at(i); + _update_options_menu(); + // TODO: Make indication for the existed custom nodes with that script on graph to be disabled. + break; + } + } + return; + } + Dictionary dict = get_custom_node_data(ref); + + bool found_type = false; + bool need_rebuild = false; + + for (int i = 0; i < add_options.size(); i++) { + if (add_options[i].is_custom && add_options[i].script == scr) { + found_type = true; + + add_options.write[i].name = dict["name"]; + add_options.write[i].return_type = dict["return_icon_type"]; + add_options.write[i].description = dict["description"]; + add_options.write[i].category = dict["category"]; + add_options.write[i].highend = dict["highend"]; + + int max_type = 0; + int type_offset = 0; + switch (visual_shader->get_mode()) { + case Shader::MODE_CANVAS_ITEM: + case Shader::MODE_SPATIAL: { + max_type = 3; + } break; + case Shader::MODE_PARTICLES: { + max_type = 5; + type_offset = 3; + } break; + case Shader::MODE_SKY: { + max_type = 1; + type_offset = 8; + } break; + case Shader::MODE_FOG: { + max_type = 1; + type_offset = 9; + } break; + default: { + } break; + } + max_type = type_offset + max_type; + + for (int t = type_offset; t < max_type; t++) { + VisualShader::Type type = (VisualShader::Type)t; + Vector<int> nodes = visual_shader->get_node_list(type); + + List<VisualShader::Connection> node_connections; + visual_shader->get_node_connections(type, &node_connections); + + List<VisualShader::Connection> custom_node_input_connections; + List<VisualShader::Connection> custom_node_output_connections; + for (const VisualShader::Connection &E : node_connections) { + int from = E.from_node; + int from_idx = E.from_port; + int to = E.to_node; + int to_idx = E.to_port; + + if (graph_plugin->get_node_script(from) == scr) { + custom_node_output_connections.push_back({ from, from_idx, to, to_idx }); + } else if (graph_plugin->get_node_script(to) == scr) { + custom_node_input_connections.push_back({ from, from_idx, to, to_idx }); + } + } + + for (int j = 0; j < nodes.size(); j++) { + int node_id = nodes[j]; + + Ref<VisualShaderNode> vsnode = visual_shader->get_node(type, node_id); + if (vsnode.is_null()) { + continue; + } + Ref<VisualShaderNodeCustom> custom_node = Ref<VisualShaderNodeCustom>(vsnode.ptr()); + if (custom_node.is_null() || custom_node->get_script() != scr) { + continue; + } + need_rebuild = true; + + // Removes invalid connections. + { + int prev_input_port_count = custom_node->get_input_port_count(); + int prev_output_port_count = custom_node->get_output_port_count(); + + custom_node->update_ports(); + + int input_port_count = custom_node->get_input_port_count(); + int output_port_count = custom_node->get_output_port_count(); + + if (output_port_count != prev_output_port_count) { + for (const VisualShader::Connection &E : custom_node_output_connections) { + int from = E.from_node; + int from_idx = E.from_port; + int to = E.to_node; + int to_idx = E.to_port; + + if (from_idx >= output_port_count) { + visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx); + graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx); + } + } + } + if (input_port_count != prev_input_port_count) { + for (const VisualShader::Connection &E : custom_node_input_connections) { + int from = E.from_node; + int from_idx = E.from_port; + int to = E.to_node; + int to_idx = E.to_port; + + if (to_idx >= input_port_count) { + visual_shader->disconnect_nodes(type, from, from_idx, to, to_idx); + graph_plugin->disconnect_nodes(type, from, from_idx, to, to_idx); + } + } + } + } + + graph_plugin->update_node(type, node_id); + } + } + break; + } + } + + if (!found_type) { + add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]); + } + + // To prevent updating options multiple times when multiple scripts are saved. + if (!_block_update_options_menu) { + _block_update_options_menu = true; + + call_deferred(SNAME("_update_options_menu_deferred")); + } + + // To prevent rebuilding the shader multiple times when multiple scripts are saved. + if (need_rebuild && !_block_rebuild_shader) { + _block_rebuild_shader = true; + + call_deferred(SNAME("_rebuild_shader_deferred")); + } +} + +void VisualShaderEditor::_update_options_menu_deferred() { + _update_options_menu(); + + _block_update_options_menu = false; +} + +void VisualShaderEditor::_rebuild_shader_deferred() { + if (visual_shader.is_valid()) { + visual_shader->rebuild(); + } + + _block_rebuild_shader = false; +} + bool VisualShaderEditor::_is_available(int p_mode) { int current_mode = edit_type->get_selected(); @@ -1243,57 +1474,10 @@ void VisualShaderEditor::_update_nodes() { if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { continue; } - - String name; - if (ref->has_method("_get_name")) { - name = (String)ref->call("_get_name"); - } else { - name = "Unnamed"; - } - - String description = ""; - if (ref->has_method("_get_description")) { - description = (String)ref->call("_get_description"); - } - - int return_icon_type = -1; - if (ref->has_method("_get_return_icon_type")) { - return_icon_type = (int)ref->call("_get_return_icon_type"); - } - - String category = ""; - if (ref->has_method("_get_category")) { - category = (String)ref->call("_get_category"); - } - - String subcategory = ""; - if (ref->has_method("_get_subcategory")) { - subcategory = (String)ref->call("_get_subcategory"); - } - - bool highend = false; - if (ref->has_method("_is_highend")) { - highend = (bool)ref->call("_is_highend"); - } - - Dictionary dict; - dict["name"] = name; - dict["script"] = scr; - dict["description"] = description; - dict["return_icon_type"] = return_icon_type; - - category = category.rstrip("/"); - category = category.lstrip("/"); - category = "Addons/" + category; - if (!subcategory.is_empty()) { - category += "/" + subcategory; - } - - dict["category"] = category; - dict["highend"] = highend; + Dictionary dict = get_custom_node_data(ref); String key; - key = category + "/" + name; + key = String(dict["category"]) + "/" + String(dict["name"]); added[key] = dict; } @@ -4694,6 +4878,8 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_update_constant", &VisualShaderEditor::_update_constant); ClassDB::bind_method("_update_parameter", &VisualShaderEditor::_update_parameter); ClassDB::bind_method("_expand_output_port", &VisualShaderEditor::_expand_output_port); + ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred); + ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred); ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); @@ -4704,6 +4890,7 @@ void VisualShaderEditor::_bind_methods() { VisualShaderEditor::VisualShaderEditor() { ShaderLanguage::get_keyword_list(&keyword_list); + EditorNode::get_singleton()->connect("resource_saved", callable_mp(this, &VisualShaderEditor::update_custom_type)); graph = memnew(GraphEdit); graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL); @@ -5209,6 +5396,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("NodePositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("CameraPositionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("CameraDirectionWorld", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraVisibleLayers", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("NodePositionView", "Input/Vertex", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_VERTEX, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Binormal", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); @@ -5228,6 +5416,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("NodePositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_world", "NODE_POSITION_WORLD"), { "node_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("CameraPositionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_position_world", "CAMERA_POSITION_WORLD"), { "camera_position_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("CameraDirectionWorld", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_direction_world", "CAMERA_DIRECTION_WORLD"), { "camera_direction_world" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CameraVisibleLayers", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "camera_visible_layers", "CAMERA_VISIBLE_LAYERS"), { "camera_visible_layers" }, VisualShaderNode::PORT_TYPE_SCALAR_INT, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("NodePositionView", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "node_position_view", "NODE_POSITION_VIEW"), { "node_position_view" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL)); add_options.push_back(AddOption("Albedo", "Input/Light", "VisualShaderNodeInput", vformat(input_param_for_light_shader_mode, "albedo", "ALBEDO"), { "albedo" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_LIGHT, Shader::MODE_SPATIAL)); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index e9d6257f81..d559237569 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -34,11 +34,17 @@ #include "editor/editor_plugin.h" #include "editor/editor_properties.h" #include "editor/plugins/editor_resource_conversion_plugin.h" +#include "scene/resources/syntax_highlighter.h" #include "scene/resources/visual_shader.h" +class CodeEdit; class CurveEditor; class GraphEdit; class GraphNode; +class MenuButton; +class PopupPanel; +class RichTextLabel; +class Tree; class VisualShaderEditor; @@ -127,6 +133,7 @@ public: void update_curve_xyz(int p_node_id); void set_expression(VisualShader::Type p_type, int p_node_id, const String &p_expression); int get_constant_index(float p_constant) const; + Ref<Script> get_node_script(int p_node_id) const; void update_node_size(int p_node_id); void update_theme(); VisualShader::Type get_shader_type() const; @@ -184,6 +191,9 @@ class VisualShaderEditor : public VBoxContainer { PanelContainer *error_panel = nullptr; Label *error_label = nullptr; + bool _block_update_options_menu = false; + bool _block_rebuild_shader = false; + Point2 saved_node_pos; bool saved_node_pos_dirty = false; @@ -491,6 +501,9 @@ class VisualShaderEditor : public VBoxContainer { void _update_parameter_refs(HashSet<String> &p_names); void _update_varyings(); + void _update_options_menu_deferred(); + void _rebuild_shader_deferred(); + void _visibility_changed(); protected: @@ -498,7 +511,6 @@ protected: static void _bind_methods(); public: - void update_nodes(); void add_plugin(const Ref<VisualShaderNodePlugin> &p_plugin); void remove_plugin(const Ref<VisualShaderNodePlugin> &p_plugin); @@ -507,6 +519,9 @@ public: void clear_custom_types(); void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend); + Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node); + void update_custom_type(const Ref<Resource> &p_resource); + virtual Size2 get_minimum_size() const override; void edit(VisualShader *p_visual_shader); VisualShaderEditor(); diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp index 90738a59e8..e07c672f5c 100644 --- a/editor/project_converter_3_to_4.cpp +++ b/editor/project_converter_3_to_4.cpp @@ -593,6 +593,7 @@ static const char *gdscript_function_renames[][2] = { { "is_abs_path", "is_absolute_path" }, // String { "is_valid_integer", "is_valid_int" }, // String { "linear_interpolate", "lerp" }, // Color + { "find_last", "rfind" }, // Array, String { "to_ascii", "to_ascii_buffer" }, // String { "to_utf8", "to_utf8_buffer" }, // String { "to_wchar", "to_utf32_buffer" }, // String // TODO - utf32 or utf16? @@ -1397,7 +1398,7 @@ static const char *class_renames[][2] = { // { "Physics2DDirectBodyStateSW", "GodotPhysicsDirectBodyState2D" }, // Class is not visible in ClassDB // { "Physics2DShapeQueryResult", "PhysicsShapeQueryResult2D" }, // Class is not visible in ClassDB // { "PhysicsShapeQueryResult", "PhysicsShapeQueryResult3D" }, // Class is not visible in ClassDB - // { "NativeScript","NativeExtension"}, ?? + // { "NativeScript","GDExtension"}, ?? { "ARVRAnchor", "XRAnchor3D" }, { "ARVRCamera", "XRCamera3D" }, { "ARVRController", "XRController3D" }, @@ -2679,7 +2680,7 @@ bool ProjectConverter3To4::test_array_names() { // List of excluded functions from builtin types and global namespace, because currently it is not possible to get list of functions from them. // This will be available when https://github.com/godotengine/godot/pull/49053 or similar will be included into Godot. - static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "clamp", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "snapped", "remap", nullptr }; + static const char *builtin_types_excluded_functions[] = { "dict_to_inst", "inst_to_dict", "bytes_to_var", "bytes_to_var_with_objects", "db_to_linear", "deg_to_rad", "linear_to_db", "rad_to_deg", "randf_range", "snapped", "str_to_var", "var_to_str", "var_to_bytes", "var_to_bytes_with_objects", "move_toward", "uri_encode", "uri_decode", "remove_at", "get_rotation_quaternion", "clamp", "grow_side", "is_absolute_path", "is_valid_int", "lerp", "to_ascii_buffer", "to_utf8_buffer", "to_utf32_buffer", "snapped", "remap", "rfind", nullptr }; for (int current_index = 0; builtin_types_excluded_functions[current_index]; current_index++) { all_functions.insert(builtin_types_excluded_functions[current_index]); } diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index 02d59921bf..249504b6e8 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -49,6 +49,7 @@ #include "editor/editor_vcs_interface.h" #include "main/main.h" #include "scene/gui/center_container.h" +#include "scene/gui/check_box.h" #include "scene/gui/line_edit.h" #include "scene/gui/margin_container.h" #include "scene/gui/panel_container.h" @@ -435,17 +436,17 @@ private: return; } - ProjectSettings *current = memnew(ProjectSettings); - - int err = current->setup(dir2, ""); + // Load project.godot as ConfigFile to set the new name. + ConfigFile cfg; + String project_godot = dir2.path_join("project.godot"); + Error err = cfg.load(project_godot); if (err != OK) { - set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR); + set_message(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err), MESSAGE_ERROR); } else { - ProjectSettings::CustomMap edited_settings; - edited_settings["application/config/name"] = project_name->get_text().strip_edges(); - - if (current->save_custom(dir2.path_join("project.godot"), edited_settings, Vector<String>(), true) != OK) { - set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR); + cfg.set_value("application", "config/name", project_name->get_text().strip_edges()); + err = cfg.save(project_godot); + if (err != OK) { + set_message(vformat(TTR("Couldn't save project at '%s' (error %d)."), project_godot, err), MESSAGE_ERROR); } } @@ -693,18 +694,19 @@ public: default_files_container->hide(); get_ok_button()->set_disabled(false); - ProjectSettings *current = memnew(ProjectSettings); - - int err = current->setup(project_path->get_text(), ""); + // Fetch current name from project.godot to prefill the text input. + ConfigFile cfg; + String project_godot = project_path->get_text().path_join("project.godot"); + Error err = cfg.load(project_godot); if (err != OK) { - set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR); + set_message(vformat(TTR("Couldn't load project at '%s' (error %d). It may be missing or corrupted."), project_godot, err), MESSAGE_ERROR); status_rect->show(); msg->show(); get_ok_button()->set_disabled(true); - } else if (current->has_setting("application/config/name")) { - String proj = current->get("application/config/name"); - project_name->set_text(proj); - _text_changed(proj); + } else { + String cur_name = cfg.get_value("application", "config/name", ""); + project_name->set_text(cur_name); + _text_changed(cur_name); } project_name->call_deferred(SNAME("grab_focus")); @@ -1251,7 +1253,6 @@ void ProjectList::migrate_config() { if (FileAccess::exists(_config_path)) { return; } - print_line("Migrating legacy project list"); List<PropertyInfo> properties; EditorSettings::get_singleton()->get_property_list(&properties); @@ -1264,6 +1265,8 @@ void ProjectList::migrate_config() { } String path = EDITOR_GET(property_key); + print_line("Migrating legacy project '" + path + "'."); + String favoriteKey = "favorite_projects/" + property_key.get_slice("/", 1); bool favorite = EditorSettings::get_singleton()->has_setting(favoriteKey); add_project(path, favorite); diff --git a/editor/project_manager.h b/editor/project_manager.h index 7c05429dde..de4db2944f 100644 --- a/editor/project_manager.h +++ b/editor/project_manager.h @@ -38,6 +38,7 @@ #include "scene/gui/scroll_container.h" #include "scene/gui/tree.h" +class CheckBox; class ProjectDialog; class ProjectList; diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 28111bed58..b406b2a1ce 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -274,10 +274,14 @@ void ProjectSettingsEditor::_add_feature_overrides() { presets.insert("s3tc"); presets.insert("etc"); presets.insert("etc2"); + presets.insert("editor"); + presets.insert("template_debug"); + presets.insert("template_release"); presets.insert("debug"); presets.insert("release"); - presets.insert("editor"); - presets.insert("standalone"); + presets.insert("template"); + presets.insert("double"); + presets.insert("single"); presets.insert("32"); presets.insert("64"); presets.insert("movie"); diff --git a/editor/register_editor_types.cpp b/editor/register_editor_types.cpp index d3097a694e..f301ff5c6b 100644 --- a/editor/register_editor_types.cpp +++ b/editor/register_editor_types.cpp @@ -30,8 +30,6 @@ #include "register_editor_types.h" -#include "core/extension/native_extension_manager.h" - #include "editor/animation_track_editor.h" #include "editor/debugger/debug_adapter/debug_adapter_server.h" #include "editor/editor_command_palette.h" @@ -43,6 +41,7 @@ #include "editor/editor_resource_picker.h" #include "editor/editor_resource_preview.h" #include "editor/editor_run_script.h" +#include "editor/editor_settings.h" #include "editor/editor_translation_parser.h" #include "editor/editor_undo_redo_manager.h" #include "editor/filesystem_dock.h" diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp index 74c123d942..40683e2938 100644 --- a/editor/rename_dialog.cpp +++ b/editor/rename_dialog.cpp @@ -42,6 +42,7 @@ #include "modules/regex/regex.h" #include "plugins/script_editor_plugin.h" #include "scene/gui/control.h" +#include "scene/gui/grid_container.h" #include "scene/gui/label.h" #include "scene/gui/separator.h" #include "scene/gui/tab_container.h" diff --git a/editor/reparent_dialog.cpp b/editor/reparent_dialog.cpp index 75098b25b1..37712d4197 100644 --- a/editor/reparent_dialog.cpp +++ b/editor/reparent_dialog.cpp @@ -33,6 +33,7 @@ #include "core/string/print_string.h" #include "scene/gui/box_container.h" #include "scene/gui/label.h" +#include "scene/gui/tree.h" void ReparentDialog::_notification(int p_what) { switch (p_what) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 9c3ef4cecc..96688a3614 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -41,14 +41,17 @@ #include "editor/editor_file_dialog.h" #include "editor/editor_node.h" #include "editor/editor_paths.h" +#include "editor/editor_quick_open.h" #include "editor/editor_scale.h" #include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" +#include "editor/inspector_dock.h" #include "editor/multi_node_edit.h" #include "editor/plugins/animation_player_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" #include "editor/plugins/node_3d_editor_plugin.h" #include "editor/plugins/script_editor_plugin.h" +#include "editor/reparent_dialog.h" #include "editor/shader_create_dialog.h" #include "scene/main/window.h" #include "scene/property_utils.h" @@ -1153,11 +1156,13 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { if (TOOL_CREATE_FAVORITE == p_tool) { String name = selected_favorite_root.get_slicec(' ', 0); if (ScriptServer::is_global_class(name)) { - new_node = Object::cast_to<Node>(ClassDB::instantiate(ScriptServer::get_global_class_native_base(name))); Ref<Script> scr = ResourceLoader::load(ScriptServer::get_global_class_path(name), "Script"); - if (new_node && scr.is_valid()) { - new_node->set_script(scr); - new_node->set_name(name); + if (scr.is_valid()) { + new_node = Object::cast_to<Node>(ClassDB::instantiate(scr->get_instance_base_type())); + if (new_node) { + new_node->set_script(scr); + new_node->set_name(name); + } } } else { new_node = Object::cast_to<Node>(ClassDB::instantiate(selected_favorite_root)); @@ -2448,9 +2453,12 @@ void SceneTreeDock::_new_scene_from(String p_file) { Node *copy = base->duplicate_from_editor(duplimap); if (copy) { + // Handle Unique Nodes. for (int i = 0; i < copy->get_child_count(false); i++) { _set_node_owner_recursive(copy->get_child(i, false), copy); } + // Root node cannot ever be unique name in its own Scene! + copy->set_unique_name_in_owner(false); Ref<PackedScene> sdata = memnew(PackedScene); Error err = sdata->pack(copy); diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h index 6ec9d31ca8..ac368e1aab 100644 --- a/editor/scene_tree_dock.h +++ b/editor/scene_tree_dock.h @@ -31,21 +31,17 @@ #ifndef SCENE_TREE_DOCK_H #define SCENE_TREE_DOCK_H -#include "editor/create_dialog.h" +#include "scene_tree_editor.h" + #include "editor/editor_data.h" -#include "editor/editor_quick_open.h" -#include "editor/groups_editor.h" -#include "editor/reparent_dialog.h" #include "editor/script_create_dialog.h" -#include "scene/animation/animation_player.h" #include "scene/gui/box_container.h" -#include "scene/gui/button.h" -#include "scene/gui/control.h" -#include "scene/gui/label.h" -#include "scene/gui/popup_menu.h" -#include "scene/gui/tree.h" -#include "scene_tree_editor.h" +#include "scene/resources/animation.h" +class EditorQuickOpen; +class MenuButton; +class ReparentDialog; +class ShaderCreateDialog; class TextureRect; #include "modules/modules_enabled.gen.h" // For regex. @@ -53,8 +49,6 @@ class TextureRect; class RenameDialog; #endif // MODULE_REGEX_ENABLED -class ShaderCreateDialog; - class SceneTreeDock : public VBoxContainer { GDCLASS(SceneTreeDock, VBoxContainer); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 46d3502a24..092ef30678 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -32,10 +32,10 @@ #include "core/config/project_settings.h" #include "core/object/message_queue.h" -#include "core/string/print_string.h" #include "editor/editor_file_system.h" #include "editor/editor_node.h" #include "editor/editor_scale.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "editor/node_dock.h" #include "editor/plugins/animation_player_editor_plugin.h" diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 33ef5dbcb3..c1afcf0f45 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -32,8 +32,6 @@ #define SCENE_TREE_EDITOR_H #include "editor/editor_data.h" -#include "editor/editor_settings.h" -#include "scene/gui/button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 4a3b0e979f..52f4ae553f 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -107,7 +107,15 @@ static Vector<String> _get_hierarchy(String p_class_name) { void ScriptCreateDialog::_notification(int p_what) { switch (p_what) { - case NOTIFICATION_ENTER_TREE: { + case NOTIFICATION_ENTER_TREE: + case NOTIFICATION_THEME_CHANGED: { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + Ref<Texture2D> language_icon = get_theme_icon(ScriptServer::get_language(i)->get_type(), SNAME("EditorIcons")); + if (language_icon.is_valid()) { + language_menu->set_item_icon(i, language_icon); + } + } + String last_language = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); if (!last_language.is_empty()) { for (int i = 0; i < language_menu->get_item_count(); i++) { @@ -120,15 +128,9 @@ void ScriptCreateDialog::_notification(int p_what) { } else { language_menu->select(default_language); } - - [[fallthrough]]; - } - case NOTIFICATION_THEME_CHANGED: { - for (int i = 0; i < ScriptServer::get_language_count(); i++) { - Ref<Texture2D> language_icon = get_theme_icon(ScriptServer::get_language(i)->get_type(), SNAME("EditorIcons")); - if (language_icon.is_valid()) { - language_menu->set_item_icon(i, language_icon); - } + if (EditorSettings::get_singleton()->has_meta("script_setup_use_script_templates")) { + is_using_templates = bool(EditorSettings::get_singleton()->get_meta("script_setup_use_script_templates")); + use_templates->set_pressed(is_using_templates); } path_button->set_icon(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons"))); @@ -331,7 +333,12 @@ void ScriptCreateDialog::_template_changed(int p_template) { EditorSettings::get_singleton()->set_project_metadata("script_setup", "templates_dictionary", dic_templates_project); } else { // Save template info to editor dictionary (not a project template). - templates_dictionary[parent_name->get_text()] = sinfo.get_hash(); + Dictionary dic_templates; + if (EditorSettings::get_singleton()->has_meta("script_setup_templates_dictionary")) { + dic_templates = (Dictionary)EditorSettings::get_singleton()->get_meta("script_setup_templates_dictionary"); + } + dic_templates[parent_name->get_text()] = sinfo.get_hash(); + EditorSettings::get_singleton()->set_meta("script_setup_templates_dictionary", dic_templates); // Remove template from project dictionary as we last used an editor level template. Dictionary dic_templates_project = EditorSettings::get_singleton()->get_project_metadata("script_setup", "templates_dictionary", Dictionary()); if (dic_templates_project.has(parent_name->get_text())) { @@ -480,6 +487,7 @@ void ScriptCreateDialog::_built_in_pressed() { void ScriptCreateDialog::_use_template_pressed() { is_using_templates = use_templates->is_pressed(); + EditorSettings::get_singleton()->set_meta("script_setup_use_script_templates", is_using_templates); _update_dialog(); } @@ -597,6 +605,10 @@ void ScriptCreateDialog::_update_template_menu() { if (is_language_using_templates) { // Get the latest templates used for each type of node from project settings then global settings. Dictionary last_local_templates = EditorSettings::get_singleton()->get_project_metadata("script_setup", "templates_dictionary", Dictionary()); + Dictionary last_global_templates; + if (EditorSettings::get_singleton()->has_meta("script_setup_templates_dictionary")) { + last_global_templates = (Dictionary)EditorSettings::get_singleton()->get_meta("script_setup_templates_dictionary"); + } String inherits_base_type = parent_name->get_text(); // If it inherits from a script, get its parent class first. @@ -651,7 +663,7 @@ void ScriptCreateDialog::_update_template_menu() { // Check for last used template for this node in project settings then in global settings. if (last_local_templates.has(parent_name->get_text()) && t.get_hash() == String(last_local_templates[parent_name->get_text()])) { last_used_template = id; - } else if (last_used_template == -1 && templates_dictionary.has(parent_name->get_text()) && t.get_hash() == String(templates_dictionary[parent_name->get_text()])) { + } else if (last_used_template == -1 && last_global_templates.has(parent_name->get_text()) && t.get_hash() == String(last_global_templates[parent_name->get_text()])) { last_used_template = id; } t.id = id; diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index fb1a49a1ca..25428508da 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -83,7 +83,6 @@ class ScriptCreateDialog : public ConfirmationDialog { int current_language; int default_language; bool re_check_path = false; - Dictionary templates_dictionary; Control *path_controls[2]; Control *name_controls[2]; diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp index 22a1d49422..b778262fed 100644 --- a/editor/shader_globals_editor.cpp +++ b/editor/shader_globals_editor.cpp @@ -69,28 +69,12 @@ static const char *global_var_type_names[RS::GLOBAL_VAR_TYPE_MAX] = { class ShaderGlobalsEditorInterface : public Object { GDCLASS(ShaderGlobalsEditorInterface, Object) - void _var_changed() { - emit_signal(SNAME("var_changed")); - } - -protected: - static void _bind_methods() { - ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed); - ADD_SIGNAL(MethodInfo("var_changed")); - } - - bool _set(const StringName &p_name, const Variant &p_value) { - Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name); - - if (existing.get_type() == Variant::NIL) { - return false; - } - + void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) { Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); undo_redo->create_action(TTR("Set Shader Global Variable")); undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value); - undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, existing); + undo_redo->add_undo_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_prev_value); RS::GlobalShaderParameterType type = RS::get_singleton()->global_shader_parameter_get_type(p_name); Dictionary gv; gv["type"] = global_var_type_names[type]; @@ -111,8 +95,29 @@ protected: undo_redo->add_do_method(this, "_var_changed"); undo_redo->add_undo_method(this, "_var_changed"); block_update = true; - undo_redo->commit_action(false); + undo_redo->commit_action(); block_update = false; + } + + void _var_changed() { + emit_signal(SNAME("var_changed")); + } + +protected: + static void _bind_methods() { + ClassDB::bind_method("_set_var", &ShaderGlobalsEditorInterface::_set_var); + ClassDB::bind_method("_var_changed", &ShaderGlobalsEditorInterface::_var_changed); + ADD_SIGNAL(MethodInfo("var_changed")); + } + + bool _set(const StringName &p_name, const Variant &p_value) { + Variant existing = RS::get_singleton()->global_shader_parameter_get(p_name); + + if (existing.get_type() == Variant::NIL) { + return false; + } + + call_deferred("_set_var", p_name, p_value, existing); return true; } diff --git a/editor/translations/extract.py b/editor/translations/extract.py index cecdb3939d..04661abcbd 100755 --- a/editor/translations/extract.py +++ b/editor/translations/extract.py @@ -71,11 +71,24 @@ matches.sort() remaps = {} remap_re = re.compile(r'^\t*capitalize_string_remaps\["(?P<from>.+)"\] = (String::utf8\()?"(?P<to>.+)"') +stop_words = set() +stop_words_re = re.compile(r'^\t*"(?P<word>.+)",') +is_inside_stop_words = False with open("editor/editor_property_name_processor.cpp") as f: for line in f: - m = remap_re.search(line) - if m: - remaps[m.group("from")] = m.group("to") + if is_inside_stop_words: + m = stop_words_re.search(line) + if m: + stop_words.add(m.group("word")) + else: + is_inside_stop_words = False + else: + m = remap_re.search(line) + if m: + remaps[m.group("from")] = m.group("to") + + if not is_inside_stop_words and not stop_words: + is_inside_stop_words = "stop_words = " in line main_po = """ @@ -147,9 +160,12 @@ capitalize_re = re.compile(r"(?<=\D)(?=\d)|(?<=\d)(?=\D([a-z]|\d))") def _process_editor_string(name): # See EditorPropertyNameProcessor::process_string(). capitalized_parts = [] - for segment in name.split("_"): - if not segment: + parts = list(filter(bool, name.split("_"))) # Non-empty only. + for i, segment in enumerate(parts): + if i > 0 and i + 1 < len(parts) and segment in stop_words: + capitalized_parts.append(segment) continue + remapped = remaps.get(segment) if remapped: capitalized_parts.append(remapped) |