From 7776b47489f767cd8f877873837d2bda58b7ca15 Mon Sep 17 00:00:00 2001 From: SaracenOne Date: Wed, 4 May 2022 01:17:08 +0100 Subject: [PATCH] Add read-only mode to AnimationEditor for foreign resources. --- editor/animation_bezier_editor.cpp | 345 ++++++++++-------- editor/animation_bezier_editor.h | 3 +- editor/animation_track_editor.cpp | 331 ++++++++++------- editor/animation_track_editor.h | 10 +- editor/plugins/animation_library_editor.cpp | 139 +++++-- .../animation_player_editor_plugin.cpp | 109 +++++- 6 files changed, 618 insertions(+), 319 deletions(-) diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp index 44e04efb5d0..5845e66998a 100644 --- a/editor/animation_bezier_editor.cpp +++ b/editor/animation_bezier_editor.cpp @@ -328,6 +328,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) { } } + Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")); + Ref remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")); float remove_hpos = limit - hsep - remove->get_width(); @@ -402,7 +404,11 @@ void AnimationBezierTrackEdit::_notification(int p_what) { float icon_start_height = vofs + rect.size.y / 2; Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2, remove->get_width(), remove->get_height()); - draw_texture(remove, remove_rect.position); + if (read_only) { + draw_texture(remove, remove_rect.position, dc); + } else { + draw_texture(remove, remove_rect.position); + } Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2, lock->get_width(), lock->get_height()); if (locked_tracks.has(current_track)) { @@ -632,8 +638,9 @@ Ref AnimationBezierTrackEdit::get_animation() const { return animation; } -void AnimationBezierTrackEdit::set_animation_and_track(const Ref &p_animation, int p_track) { +void AnimationBezierTrackEdit::set_animation_and_track(const Ref &p_animation, int p_track, bool p_read_only) { animation = p_animation; + read_only = p_read_only; selected_track = p_track; update(); } @@ -715,7 +722,7 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) { continue; // Skip track due to not selected. } - set_animation_and_track(animation, i); + set_animation_and_track(animation, i, read_only); break; } } @@ -819,12 +826,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { if (p_event->is_pressed()) { if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) { - duplicate_selection(); + if (!read_only) { + duplicate_selection(); + } accept_event(); } if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) { - delete_selection(); + if (!read_only) { + delete_selection(); + } accept_event(); } } @@ -917,26 +928,28 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { menu_insert_key = mb->get_position(); if (menu_insert_key.x >= limit && menu_insert_key.x <= get_size().width) { - Vector2 popup_pos = get_screen_position() + mb->get_position(); + if (!read_only) { + Vector2 popup_pos = get_screen_position() + mb->get_position(); - menu->clear(); - if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) { - menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT); - } - if (selection.size()) { - menu->add_separator(); - menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE); - menu->add_separator(); - menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE); - menu->add_separator(); - menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE); - menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED); - } + menu->clear(); + if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) { + menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT); + } + if (selection.size()) { + menu->add_separator(); + menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE); + menu->add_separator(); + menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE); + menu->add_separator(); + menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE); + menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED); + } - if (menu->get_item_count()) { - menu->reset_size(); - menu->set_position(popup_pos); - menu->popup(); + if (menu->get_item_count()) { + menu->reset_size(); + menu->set_position(popup_pos); + menu->popup(); + } } } } @@ -945,7 +958,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { for (const KeyValue &E : subtracks) { if (E.value.has_point(mb->get_position())) { if (!locked_tracks.has(E.key) && !hidden_tracks.has(E.key)) { - set_animation_and_track(animation, E.key); + set_animation_and_track(animation, E.key, read_only); _clear_selection(); } return; @@ -958,30 +971,32 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { for (const KeyValue &I : track_icons) { if (I.value.has_point(mb->get_position())) { if (I.key == REMOVE_ICON) { - undo_redo->create_action("Remove Bezier Track"); + if (!read_only) { + undo_redo->create_action("Remove Bezier Track"); - undo_redo->add_do_method(this, "_update_locked_tracks_after", track); - undo_redo->add_do_method(this, "_update_hidden_tracks_after", track); + undo_redo->add_do_method(this, "_update_locked_tracks_after", track); + undo_redo->add_do_method(this, "_update_hidden_tracks_after", track); - undo_redo->add_do_method(animation.ptr(), "remove_track", track); + undo_redo->add_do_method(animation.ptr(), "remove_track", track); - undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track); - undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track)); + undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track); + undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track)); - for (int i = 0; i < animation->track_get_key_count(track); ++i) { - undo_redo->add_undo_method( - animation.ptr(), - "bezier_track_insert_key", - track, animation->track_get_key_time(track, i), - animation->bezier_track_get_key_value(track, i), - animation->bezier_track_get_key_in_handle(track, i), - animation->bezier_track_get_key_out_handle(track, i), - animation->bezier_track_get_key_handle_mode(track, i)); + for (int i = 0; i < animation->track_get_key_count(track); ++i) { + undo_redo->add_undo_method( + animation.ptr(), + "bezier_track_insert_key", + track, animation->track_get_key_time(track, i), + animation->bezier_track_get_key_value(track, i), + animation->bezier_track_get_key_in_handle(track, i), + animation->bezier_track_get_key_out_handle(track, i), + animation->bezier_track_get_key_handle_mode(track, i)); + } + + undo_redo->commit_action(); + + selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1); } - - undo_redo->commit_action(); - - selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1); return; } else if (I.key == LOCK_ICON) { if (locked_tracks.has(track)) { @@ -991,7 +1006,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { if (selected_track == track) { for (int i = 0; i < animation->get_track_count(); ++i) { if (!locked_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) { - set_animation_and_track(animation, i); + set_animation_and_track(animation, i, read_only); break; } } @@ -1007,7 +1022,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { if (selected_track == track) { for (int i = 0; i < animation->get_track_count(); ++i) { if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) { - set_animation_and_track(animation, i); + set_animation_and_track(animation, i, read_only); break; } } @@ -1046,7 +1061,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { } } - set_animation_and_track(animation, track); + set_animation_and_track(animation, track, read_only); solo_track = track; } update(); @@ -1087,7 +1102,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { moving_selection_from_key = pair.second; moving_selection_from_track = pair.first; moving_selection_offset = Vector2(); - set_animation_and_track(animation, pair.first); + set_animation_and_track(animation, pair.first, read_only); selection.clear(); selection.insert(pair); update(); @@ -1096,24 +1111,26 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { } } - if (edit_points[i].in_rect.has_point(mb->get_position())) { - moving_handle = -1; - moving_handle_key = edit_points[i].key; - moving_handle_track = edit_points[i].track; - moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); - moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); - update(); - return; - } + if (!read_only) { + if (edit_points[i].in_rect.has_point(mb->get_position())) { + moving_handle = -1; + moving_handle_key = edit_points[i].key; + moving_handle_track = edit_points[i].track; + moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); + moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); + update(); + return; + } - if (edit_points[i].out_rect.has_point(mb->get_position())) { - moving_handle = 1; - moving_handle_key = edit_points[i].key; - moving_handle_track = edit_points[i].track; - moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); - moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); - update(); - return; + if (edit_points[i].out_rect.has_point(mb->get_position())) { + moving_handle = 1; + moving_handle_key = edit_points[i].key; + moving_handle_track = edit_points[i].track; + moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); + moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); + update(); + return; + } } } @@ -1191,7 +1208,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { selection.insert(IntPair(edit_points[i].track, edit_points[i].key)); if (!track_set) { track_set = true; - set_animation_and_track(animation, edit_points[i].track); + set_animation_and_track(animation, edit_points[i].track, read_only); } } } @@ -1215,7 +1232,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { float track_height = _bezier_h_to_pixel(track_h); if (abs(mb->get_position().y - track_height) < 10) { - set_animation_and_track(animation, i); + set_animation_and_track(animation, i, read_only); break; } } @@ -1229,102 +1246,106 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { } if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - undo_redo->create_action(TTR("Move Bezier Points")); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left); - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_in_handle(selected_track, moving_handle_key)); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key)); - undo_redo->commit_action(); + if (!read_only) { + undo_redo->create_action(TTR("Move Bezier Points")); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left); + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_in_handle(selected_track, moving_handle_key)); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key)); + undo_redo->commit_action(); - moving_handle = 0; - update(); + moving_handle = 0; + update(); + } } if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { - if (moving_selection) { - //combit it + if (!read_only) { + if (moving_selection) { + //combit it - undo_redo->create_action(TTR("Move Bezier Points")); + undo_redo->create_action(TTR("Move Bezier Points")); - List to_restore; - // 1-remove the 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); - } - // 2- remove overlapped keys - for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + List to_restore; + // 1-remove the 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); + } + // 2- remove overlapped keys + for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { + float newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); - int idx = animation->track_find_key(E->get().first, newtime, true); - if (idx == -1) { - continue; + int idx = animation->track_find_key(E->get().first, newtime, true); + if (idx == -1) { + continue; + } + + if (selection.has(IntPair(E->get().first, idx))) { + continue; //already in selection, don't save + } + + undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime); + AnimMoveRestore amr; + + amr.key = animation->track_get_key_value(E->get().first, idx); + amr.track = E->get().first; + amr.time = newtime; + + to_restore.push_back(amr); } - if (selection.has(IntPair(E->get().first, idx))) { - continue; //already in selection, don't save + // 3-move the keys (re insert them) + for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { + float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + Array key = animation->track_get_key_value(E->get().first, E->get().second); + float h = key[0]; + h += moving_selection_offset.y; + key[0] = h; + undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, newpos, key, 1); } - undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime); - AnimMoveRestore amr; + // 4-(undo) remove inserted keys + for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { + float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); + undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos); + } - amr.key = animation->track_get_key_value(E->get().first, idx); - amr.track = E->get().first; - amr.time = newtime; + // 5-(undo) reinsert keys + for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { + float oldpos = animation->track_get_key_time(E->get().first, E->get().second); + undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, oldpos, animation->track_get_key_value(E->get().first, E->get().second), 1); + } - to_restore.push_back(amr); + // 6-(undo) reinsert overlapped keys + for (const AnimMoveRestore &amr : to_restore) { + undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1); + } + + undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); + undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); + + // 7-reselect + + for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { + float oldpos = animation->track_get_key_time(E->get().first, E->get().second); + float newpos = editor->snap_time(oldpos + moving_selection_offset.x); + + undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos); + undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos); + } + + undo_redo->commit_action(); + + moving_selection = false; + } else if (select_single_attempt != IntPair(-1, -1)) { + selection.clear(); + selection.insert(select_single_attempt); + set_animation_and_track(animation, select_single_attempt.first, read_only); } - // 3-move the keys (re insert them) - for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); - Array key = animation->track_get_key_value(E->get().first, E->get().second); - float h = key[0]; - h += moving_selection_offset.y; - key[0] = h; - undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, newpos, key, 1); - } - - // 4-(undo) remove inserted keys - for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); - undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos); - } - - // 5-(undo) reinsert keys - for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float oldpos = animation->track_get_key_time(E->get().first, E->get().second); - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, oldpos, animation->track_get_key_value(E->get().first, E->get().second), 1); - } - - // 6-(undo) reinsert overlapped keys - for (const AnimMoveRestore &amr : to_restore) { - undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1); - } - - undo_redo->add_do_method(this, "_clear_selection_for_anim", animation); - undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation); - - // 7-reselect - - for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { - float oldpos = animation->track_get_key_time(E->get().first, E->get().second); - float newpos = editor->snap_time(oldpos + moving_selection_offset.x); - - undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos); - undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos); - } - - undo_redo->commit_action(); - - moving_selection = false; - } else if (select_single_attempt != IntPair(-1, -1)) { - selection.clear(); - selection.insert(select_single_attempt); - set_animation_and_track(animation, select_single_attempt.first); + moving_selection_attempt = false; + update(); } - - moving_selection_attempt = false; - update(); } Ref mm = p_event; @@ -1337,7 +1358,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll; float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value()); - moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key)); + if (!read_only) { + moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key)); + } update(); } @@ -1399,20 +1422,22 @@ void AnimationBezierTrackEdit::gui_input(const Ref &p_event) { bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT; if (is_finishing_key_handle_drag) { - undo_redo->create_action(TTR("Move Bezier Points")); - if (moving_handle == -1) { - double ratio = timeline->get_zoom_scale() * v_zoom; - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio); - } else if (moving_handle == 1) { - double ratio = timeline->get_zoom_scale() * v_zoom; - undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio); - undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio); - } - undo_redo->commit_action(); + if (!read_only) { + undo_redo->create_action(TTR("Move Bezier Points")); + if (moving_handle == -1) { + double ratio = timeline->get_zoom_scale() * v_zoom; + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio); + } else if (moving_handle == 1) { + double ratio = timeline->get_zoom_scale() * v_zoom; + undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio); + undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio); + } + undo_redo->commit_action(); - moving_handle = 0; - update(); + moving_handle = 0; + update(); + } } } diff --git a/editor/animation_bezier_editor.h b/editor/animation_bezier_editor.h index 22b58a6703f..070a6589ad0 100644 --- a/editor/animation_bezier_editor.h +++ b/editor/animation_bezier_editor.h @@ -54,6 +54,7 @@ class AnimationBezierTrackEdit : public Control { float play_position_pos = 0; Ref animation; + bool read_only = false; int selected_track = 0; Vector view_rects; @@ -176,7 +177,7 @@ public: Ref get_animation() const; - void set_animation_and_track(const Ref &p_animation, int p_track); + void set_animation_and_track(const Ref &p_animation, int p_track, bool p_read_only); virtual Size2 get_minimum_size() const override; void set_undo_redo(UndoRedo *p_undo_redo); diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 703cfaee3d2..757d64d5fc5 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -47,6 +47,7 @@ class AnimationTrackKeyEdit : public Object { public: bool setting = false; + bool animation_read_only = false; bool _hide_script_from_inspector() { return true; @@ -56,12 +57,17 @@ public: return true; } + bool _read_only() { + return animation_read_only; + } + static void _bind_methods() { ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj); ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed); ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector); ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path); ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo); + ClassDB::bind_method("_read_only", &AnimationTrackKeyEdit::_read_only); } void _fix_node_path(Variant &value) { @@ -702,6 +708,7 @@ class AnimationMultiTrackKeyEdit : public Object { public: bool setting = false; + bool animation_read_only = false; bool _hide_script_from_inspector() { return true; @@ -711,12 +718,17 @@ public: return true; } + bool _read_only() { + return animation_read_only; + } + static void _bind_methods() { ClassDB::bind_method("_update_obj", &AnimationMultiTrackKeyEdit::_update_obj); ClassDB::bind_method("_key_ofs_changed", &AnimationMultiTrackKeyEdit::_key_ofs_changed); ClassDB::bind_method("_hide_script_from_inspector", &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); ClassDB::bind_method("get_root_path", &AnimationMultiTrackKeyEdit::get_root_path); ClassDB::bind_method("_dont_undo_redo", &AnimationMultiTrackKeyEdit::_dont_undo_redo); + ClassDB::bind_method("_read_only", &AnimationMultiTrackKeyEdit::_read_only); } void _fix_node_path(Variant &value, NodePath &base) { @@ -1415,22 +1427,32 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) { } void AnimationTimelineEdit::_anim_loop_pressed() { - undo_redo->create_action(TTR("Change Animation Loop")); - switch (animation->get_loop_mode()) { - case Animation::LOOP_NONE: { - undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR); - } break; - case Animation::LOOP_LINEAR: { - undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG); - } break; - case Animation::LOOP_PINGPONG: { - undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE); - } break; - default: - break; + if (!read_only) { + undo_redo->create_action(TTR("Change Animation Loop")); + switch (animation->get_loop_mode()) { + case Animation::LOOP_NONE: { + undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR); + } break; + case Animation::LOOP_LINEAR: { + undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG); + } break; + case Animation::LOOP_PINGPONG: { + undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE); + } break; + default: + break; + } + undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode()); + undo_redo->commit_action(); + } else { + String base_path = animation->get_path(); + if (FileAccess::exists(base_path + ".import")) { + EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation instanced from imported scene.")); + } else { + EditorNode::get_singleton()->show_warning(TTR("Can't change loop mode on animation embedded in another scene.")); + } + update_values(); } - undo_redo->add_undo_method(animation.ptr(), "set_loop_mode", animation->get_loop_mode()); - undo_redo->commit_action(); } int AnimationTimelineEdit::get_buttons_width() const { @@ -1655,11 +1677,17 @@ void AnimationTimelineEdit::_notification(int p_what) { } } -void AnimationTimelineEdit::set_animation(const Ref &p_animation) { +void AnimationTimelineEdit::set_animation(const Ref &p_animation, bool p_read_only) { animation = p_animation; + read_only = p_read_only; + if (animation.is_valid()) { len_hb->show(); - add_track->show(); + if (read_only) { + add_track->hide(); + } else { + add_track->show(); + } play_position->show(); } else { len_hb->hide(); @@ -1981,6 +2009,8 @@ void AnimationTrackEdit::_notification(int p_what) { Color linecolor = color; linecolor.a = 0.2; + Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor")); + // NAMES AND ICONS // { @@ -2130,14 +2160,18 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += update_icon->get_width() + hsep / 2; update_mode_rect.size.x += hsep / 2; - if (animation->track_get_type(track) == Animation::TYPE_VALUE) { - draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); - update_mode_rect.size.x += down_icon->get_width(); - } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) { - Ref bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")); - update_mode_rect.size.x += down_icon->get_width(); + if (!read_only) { + if (animation->track_get_type(track) == Animation::TYPE_VALUE) { + draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); + update_mode_rect.size.x += down_icon->get_width(); + } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) { + Ref bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")); + update_mode_rect.size.x += down_icon->get_width(); - update_mode_rect = Rect2(); + update_mode_rect = Rect2(); + } else { + update_mode_rect = Rect2(); + } } else { update_mode_rect = Rect2(); } @@ -2168,7 +2202,7 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += icon->get_width() + hsep / 2; interp_mode_rect.size.x += hsep / 2; - if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) { + if (!read_only && !animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); interp_mode_rect.size.x += down_icon->get_width(); } else { @@ -2201,7 +2235,7 @@ void AnimationTrackEdit::_notification(int p_what) { ofs += icon->get_width() + hsep / 2; loop_wrap_rect.size.x += hsep / 2; - if (!animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) { + if (!read_only && !animation->track_is_compressed(track) && (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_BLEND_SHAPE || animation->track_get_type(track) == Animation::TYPE_POSITION_3D || animation->track_get_type(track) == Animation::TYPE_SCALE_3D || animation->track_get_type(track) == Animation::TYPE_ROTATION_3D)) { draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); loop_wrap_rect.size.x += down_icon->get_width(); } else { @@ -2222,7 +2256,11 @@ void AnimationTrackEdit::_notification(int p_what) { remove_rect.position.y = int(get_size().height - icon->get_height()) / 2; remove_rect.size = icon->get_size(); - draw_texture(icon, remove_rect.position); + if (read_only) { + draw_texture(icon, remove_rect.position, dc); + } else { + draw_texture(icon, remove_rect.position); + } } } @@ -2438,8 +2476,10 @@ Ref AnimationTrackEdit::get_animation() const { return animation; } -void AnimationTrackEdit::set_animation_and_track(const Ref &p_animation, int p_track) { +void AnimationTrackEdit::set_animation_and_track(const Ref &p_animation, int p_track, bool p_read_only) { animation = p_animation; + read_only = p_read_only; + track = p_track; update(); @@ -2720,17 +2760,23 @@ void AnimationTrackEdit::gui_input(const Ref &p_event) { if (p_event->is_pressed()) { if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) { - emit_signal(SNAME("duplicate_request")); + if (!read_only) { + emit_signal(SNAME("duplicate_request")); + } accept_event(); } if (ED_GET_SHORTCUT("animation_editor/duplicate_selection_transposed")->matches_event(p_event)) { - emit_signal(SNAME("duplicate_transpose_request")); + if (!read_only) { + emit_signal(SNAME("duplicate_transpose_request")); + } accept_event(); } if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) { - emit_signal(SNAME("delete_request")); + if (!read_only) { + emit_signal(SNAME("delete_request")); + } accept_event(); } } @@ -2739,79 +2785,81 @@ void AnimationTrackEdit::gui_input(const Ref &p_event) { if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { Point2 pos = mb->get_position(); - if (check_rect.has_point(pos)) { - undo_redo->create_action(TTR("Toggle Track Enabled")); - undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track)); - undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track)); - undo_redo->commit_action(); - update(); - accept_event(); - } - - // Don't overlap track keys if they start at 0. - if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) { - clicking_on_name = true; - accept_event(); - } - - if (update_mode_rect.has_point(pos)) { - if (!menu) { - menu = memnew(PopupMenu); - add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + if (!read_only) { + if (check_rect.has_point(pos)) { + undo_redo->create_action(TTR("Toggle Track Enabled")); + undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track)); + undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track)); + undo_redo->commit_action(); + update(); + accept_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(); - Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height); - menu->set_position(popup_pos); - menu->popup(); - accept_event(); - } - - if (interp_mode_rect.has_point(pos)) { - if (!menu) { - menu = memnew(PopupMenu); - add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + // Don't overlap track keys if they start at 0. + if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) { + clicking_on_name = true; + accept_event(); } - menu->clear(); - menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); - menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR); - menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC); - menu->reset_size(); - Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height); - menu->set_position(popup_pos); - menu->popup(); - accept_event(); - } + if (update_mode_rect.has_point(pos)) { + if (!menu) { + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + } + 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(); - if (loop_wrap_rect.has_point(pos)) { - if (!menu) { - menu = memnew(PopupMenu); - add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height); + menu->set_position(popup_pos); + menu->popup(); + accept_event(); } - menu->clear(); - menu->add_icon_item(get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP); - menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP); - menu->reset_size(); - Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height); - menu->set_position(popup_pos); - menu->popup(); - accept_event(); - } + if (interp_mode_rect.has_point(pos)) { + if (!menu) { + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + } + menu->clear(); + menu->add_icon_item(get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")), TTR("Nearest"), MENU_INTERPOLATION_NEAREST); + menu->add_icon_item(get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")), TTR("Linear"), MENU_INTERPOLATION_LINEAR); + menu->add_icon_item(get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons")), TTR("Cubic"), MENU_INTERPOLATION_CUBIC); + menu->reset_size(); - if (remove_rect.has_point(pos)) { - emit_signal(SNAME("remove_request"), track); - accept_event(); - return; + Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height); + menu->set_position(popup_pos); + menu->popup(); + accept_event(); + } + + if (loop_wrap_rect.has_point(pos)) { + if (!menu) { + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); + } + menu->clear(); + menu->add_icon_item(get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP); + menu->add_icon_item(get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP); + menu->reset_size(); + + Vector2 popup_pos = get_screen_position() + loop_wrap_rect.position + Vector2(0, loop_wrap_rect.size.height); + menu->set_position(popup_pos); + menu->popup(); + accept_event(); + } + + if (remove_rect.has_point(pos)) { + emit_signal(SNAME("remove_request"), track); + accept_event(); + return; + } } // Check keyframes. @@ -2871,6 +2919,11 @@ void AnimationTrackEdit::gui_input(const Ref &p_event) { moving_selection_attempt = true; moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale(); } + + if (read_only) { + moving_selection_attempt = false; + moving_selection_from_ofs = 0.0f; + } accept_event(); } } @@ -2882,33 +2935,35 @@ void AnimationTrackEdit::gui_input(const Ref &p_event) { if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) { // Can do something with menu too! show insert key. float offset = (pos.x - timeline->get_name_limit()) / timeline->get_zoom_scale(); - if (!menu) { - menu = memnew(PopupMenu); - add_child(menu); - menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); - } - - menu->clear(); - menu->add_icon_item(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")), TTR("Insert Key"), MENU_KEY_INSERT); - if (editor->is_selection_active()) { - menu->add_separator(); - menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE); - - AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player(); - if (!player->has_animation(SceneStringNames::get_singleton()->RESET) || animation != player->get_animation(SceneStringNames::get_singleton()->RESET)) { - menu->add_icon_item(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Add RESET Value(s)"), MENU_KEY_ADD_RESET); + if (!read_only) { + if (!menu) { + menu = memnew(PopupMenu); + add_child(menu); + menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); } - menu->add_separator(); - menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE); + menu->clear(); + menu->add_icon_item(get_theme_icon(SNAME("Key"), SNAME("EditorIcons")), TTR("Insert Key"), MENU_KEY_INSERT); + if (editor->is_selection_active()) { + menu->add_separator(); + menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE); + + AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player(); + if (!player->has_animation(SceneStringNames::get_singleton()->RESET) || animation != player->get_animation(SceneStringNames::get_singleton()->RESET)) { + menu->add_icon_item(get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")), TTR("Add RESET Value(s)"), MENU_KEY_ADD_RESET); + } + + menu->add_separator(); + menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE); + } + menu->reset_size(); + + menu->set_position(get_screen_position() + get_local_mouse_position()); + menu->popup(); + + insert_at_pos = offset + timeline->get_value(); + accept_event(); } - menu->reset_size(); - - menu->set_position(get_screen_position() + get_local_mouse_position()); - menu->popup(); - - insert_at_pos = offset + timeline->get_value(); - accept_event(); } } @@ -3353,7 +3408,7 @@ void AnimationTrackEditor::remove_track_edit_plugin(const Ref &p_anim) { +void AnimationTrackEditor::set_animation(const Ref &p_anim, bool p_read_only) { if (animation != p_anim && _get_track_selected() >= 0) { track_edits[_get_track_selected()]->release_focus(); } @@ -3362,7 +3417,8 @@ void AnimationTrackEditor::set_animation(const Ref &p_anim) { _clear_selection(); } animation = p_anim; - timeline->set_animation(p_anim); + read_only = p_read_only; + timeline->set_animation(p_anim, read_only); _cancel_bezier_edit(); _update_tracks(); @@ -3371,7 +3427,7 @@ void AnimationTrackEditor::set_animation(const Ref &p_anim) { animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); hscroll->show(); - edit->set_disabled(false); + edit->set_disabled(read_only); step->set_block_signals(true); _update_step_spinbox(); @@ -3500,7 +3556,7 @@ void AnimationTrackEditor::set_state(const Dictionary &p_state) { } void AnimationTrackEditor::cleanup() { - set_animation(Ref()); + set_animation(Ref(), read_only); } void AnimationTrackEditor::_name_limit_changed() { @@ -4381,6 +4437,27 @@ void AnimationTrackEditor::_update_tracks() { return; } + bool read_only = false; + if (!animation->get_path().is_resource_file()) { + int srpos = animation->get_path().find("::"); + if (srpos != -1) { + String base = animation->get_path().substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + read_only = true; + } + } else { + if (FileAccess::exists(base + ".import")) { + read_only = true; + } + } + } + } else { + if (FileAccess::exists(animation->get_path() + ".import")) { + read_only = true; + } + } + RBMap group_sort; bool use_grouping = !view_group->is_pressed(); @@ -4509,7 +4586,7 @@ void AnimationTrackEditor::_update_tracks() { track_edit->set_undo_redo(undo_redo); track_edit->set_timeline(timeline); track_edit->set_root(root); - track_edit->set_animation_and_track(animation, i); + track_edit->set_animation_and_track(animation, i, read_only); track_edit->set_play_position(timeline->get_play_position()); track_edit->set_editor(this); @@ -5181,6 +5258,7 @@ void AnimationTrackEditor::_update_key_edit() { if (selection.size() == 1) { key_edit = memnew(AnimationTrackKeyEdit); key_edit->animation = animation; + key_edit->animation_read_only = read_only; key_edit->track = selection.front()->key().track; key_edit->use_fps = timeline->is_using_fps(); @@ -5197,6 +5275,7 @@ void AnimationTrackEditor::_update_key_edit() { } else if (selection.size() > 1) { multi_key_edit = memnew(AnimationMultiTrackKeyEdit); multi_key_edit->animation = animation; + multi_key_edit->animation_read_only = read_only; RBMap> key_ofs_map; RBMap base_map; @@ -5476,7 +5555,7 @@ void AnimationTrackEditor::_cancel_bezier_edit() { void AnimationTrackEditor::_bezier_edit(int p_for_track) { _clear_selection(); // Bezier probably wants to use a separate selection mode. bezier_edit->set_root(root); - bezier_edit->set_animation_and_track(animation, p_for_track); + bezier_edit->set_animation_and_track(animation, p_for_track, read_only); scroll->hide(); bezier_edit->show(); // Search everything within the track and curve - edit it. diff --git a/editor/animation_track_editor.h b/editor/animation_track_editor.h index dede2e9bbe4..ebd208199c0 100644 --- a/editor/animation_track_editor.h +++ b/editor/animation_track_editor.h @@ -53,6 +53,8 @@ class AnimationTimelineEdit : public Range { GDCLASS(AnimationTimelineEdit, Range); Ref animation; + bool read_only = false; + AnimationTrackEdit *track_edit = nullptr; int name_limit = 0; Range *zoom = nullptr; @@ -103,7 +105,7 @@ public: float get_zoom_scale() const; virtual Size2 get_minimum_size() const override; - void set_animation(const Ref &p_animation); + void set_animation(const Ref &p_animation, bool p_read_only); void set_track_edit(AnimationTrackEdit *p_track_edit); void set_zoom(Range *p_zoom); Range *get_zoom() const { return zoom; } @@ -156,6 +158,7 @@ class AnimationTrackEdit : public Control { NodePath node_path; Ref animation; + bool read_only = false; int track = 0; Rect2 check_rect; @@ -229,7 +232,7 @@ public: AnimationTrackEditor *get_editor() const { return editor; } UndoRedo *get_undo_redo() const { return undo_redo; } NodePath get_path() const; - void set_animation_and_track(const Ref &p_animation, int p_track); + void set_animation_and_track(const Ref &p_animation, int p_track, bool p_read_only); virtual Size2 get_minimum_size() const override; void set_undo_redo(UndoRedo *p_undo_redo); @@ -287,6 +290,7 @@ class AnimationTrackEditor : public VBoxContainer { GDCLASS(AnimationTrackEditor, VBoxContainer); Ref animation; + bool read_only = false; Node *root = nullptr; MenuButton *edit = nullptr; @@ -529,7 +533,7 @@ public: void add_track_edit_plugin(const Ref &p_plugin); void remove_track_edit_plugin(const Ref &p_plugin); - void set_animation(const Ref &p_anim); + void set_animation(const Ref &p_anim, bool p_read_only); Ref get_current_animation() const; void set_root(Node *p_root); Node *get_root() const; diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp index cae33edecbc..c36ae1c5212 100644 --- a/editor/plugins/animation_library_editor.cpp +++ b/editor/plugins/animation_library_editor.cpp @@ -149,13 +149,35 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { } switch (p_id) { case FILE_MENU_SAVE_LIBRARY: { - if (al->get_path().is_resource_file()) { + if (al->get_path().is_resource_file() && !FileAccess::exists(al->get_path() + ".import")) { EditorNode::get_singleton()->save_resource(al); break; } [[fallthrough]]; } case FILE_MENU_SAVE_AS_LIBRARY: { + // Check if we're allowed to save this + { + String al_path = al->get_path(); + if (!al_path.is_resource_file()) { + int srpos = al_path.find("::"); + if (srpos != -1) { + String base = al_path.substr(0, srpos); + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + error_dialog->set_text(TTR("This animation library can't be saved because it does not belong to the edited scene. Make it unique first.")); + error_dialog->popup_centered(); + return; + } + } + } else { + if (FileAccess::exists(al_path + ".import")) { + error_dialog->set_text(TTR("This animation library can't be saved because it was imported from another file. Make it unique first.")); + error_dialog->popup_centered(); + return; + } + } + } + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_title(TTR("Save Library")); if (al->get_path().is_resource_file()) { @@ -178,6 +200,9 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { Ref ald = al->duplicate(); + // TODO: should probably make all foreign animations assigned to this library + // unique too. + UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo(); undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name)); undo_redo->add_do_method(player, "remove_animation_library", lib_name); @@ -188,19 +213,43 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { undo_redo->add_undo_method(this, "_update_editor", player); undo_redo->commit_action(); + update_tree(); + } break; case FILE_MENU_EDIT_LIBRARY: { EditorNode::get_singleton()->push_item(al.ptr()); } break; case FILE_MENU_SAVE_ANIMATION: { - if (anim->get_path().is_resource_file()) { + if (anim->get_path().is_resource_file() && !FileAccess::exists(anim->get_path() + ".import")) { EditorNode::get_singleton()->save_resource(anim); break; } [[fallthrough]]; } case FILE_MENU_SAVE_AS_ANIMATION: { + // Check if we're allowed to save this + { + String anim_path = al->get_path(); + if (!anim_path.is_resource_file()) { + int srpos = anim_path.find("::"); + if (srpos != -1) { + String base = anim_path.substr(0, srpos); + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + error_dialog->set_text(TTR("This animation can't be saved because it does not belong to the edited scene. Make it unique first.")); + error_dialog->popup_centered(); + return; + } + } + } else { + if (FileAccess::exists(anim_path + ".import")) { + error_dialog->set_text(TTR("This animation can't be saved because it was imported from another file. Make it unique first.")); + error_dialog->popup_centered(); + return; + } + } + } + file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_title(TTR("Save Animation")); if (anim->get_path().is_resource_file()) { @@ -232,6 +281,8 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) { undo_redo->add_do_method(this, "_update_editor", player); undo_redo->add_undo_method(this, "_update_editor", player); undo_redo->commit_action(); + + update_tree(); } break; case FILE_MENU_EDIT_ANIMATION: { EditorNode::get_singleton()->push_item(anim.ptr()); @@ -577,19 +628,45 @@ void AnimationLibraryEditor::update_tree() { } else { libitem->set_suffix(0, ""); } - libitem->set_editable(0, true); + + Ref al = player->call("get_animation_library", K); + bool animation_library_is_foreign = false; + String al_path = al->get_path(); + if (!al_path.is_resource_file()) { + libitem->set_text(1, TTR("[built-in]")); + libitem->set_tooltip(1, al_path); + int srpos = al_path.find("::"); + if (srpos != -1) { + String base = al_path.substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + animation_library_is_foreign = true; + libitem->set_text(1, TTR("[foreign]")); + } + } else { + if (FileAccess::exists(base + ".import")) { + animation_library_is_foreign = true; + libitem->set_text(1, TTR("[imported]")); + } + } + } + } else { + if (FileAccess::exists(al_path + ".import")) { + animation_library_is_foreign = true; + libitem->set_text(1, TTR("[imported]")); + } else { + libitem->set_text(1, al_path.get_file()); + } + } + + libitem->set_editable(0, !animation_library_is_foreign); libitem->set_metadata(0, K); libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons")); - libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, false, TTR("Add Animation to Library")); - libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, false, TTR("Load animation from file and add to library")); - libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, false, TTR("Paste Animation to Library from clipboard")); - Ref al = player->call("get_animation_library", K); - if (al->get_path().is_resource_file()) { - libitem->set_text(1, al->get_path().get_file()); - libitem->set_tooltip(1, al->get_path()); - } else { - libitem->set_text(1, TTR("[built-in]")); - } + + libitem->add_button(0, get_theme_icon("Add", "EditorIcons"), LIB_BUTTON_ADD, animation_library_is_foreign, TTR("Add Animation to Library")); + libitem->add_button(0, get_theme_icon("Load", "EditorIcons"), LIB_BUTTON_LOAD, animation_library_is_foreign, TTR("Load animation from file and add to library")); + libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste Animation to Library from clipboard")); + libitem->add_button(1, get_theme_icon("Save", "EditorIcons"), LIB_BUTTON_FILE, false, TTR("Save animation library to resource on disk")); libitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), LIB_BUTTON_DELETE, false, TTR("Remove animation library")); @@ -600,20 +677,38 @@ void AnimationLibraryEditor::update_tree() { for (const StringName &L : animations) { TreeItem *anitem = tree->create_item(libitem); anitem->set_text(0, L); - anitem->set_editable(0, true); + anitem->set_editable(0, !animation_library_is_foreign); anitem->set_metadata(0, L); anitem->set_icon(0, get_theme_icon("Animation", "EditorIcons")); - anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, false, TTR("Copy animation to clipboard")); - Ref anim = al->get_animation(L); + anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard")); - if (anim->get_path().is_resource_file()) { - anitem->set_text(1, anim->get_path().get_file()); - anitem->set_tooltip(1, anim->get_path()); - } else { + Ref anim = al->get_animation(L); + String anim_path = anim->get_path(); + if (!anim_path.is_resource_file()) { anitem->set_text(1, TTR("[built-in]")); + anitem->set_tooltip(1, anim_path); + int srpos = anim_path.find("::"); + if (srpos != -1) { + String base = anim_path.substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + anitem->set_text(1, TTR("[foreign]")); + } + } else { + if (FileAccess::exists(base + ".import")) { + anitem->set_text(1, TTR("[imported]")); + } + } + } + } else { + if (FileAccess::exists(anim_path + ".import")) { + anitem->set_text(1, TTR("[imported]")); + } else { + anitem->set_text(1, anim_path.get_file()); + } } - anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, false, TTR("Save animation to resource on disk")); - anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, false, TTR("Remove animation from Library")); + anitem->add_button(1, get_theme_icon("Save", "EditorIcons"), ANIM_BUTTON_FILE, animation_library_is_foreign, TTR("Save animation to resource on disk")); + anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library")); } } } diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp index f493c4515c9..eef38e11552 100644 --- a/editor/plugins/animation_player_editor_plugin.cpp +++ b/editor/plugins/animation_player_editor_plugin.cpp @@ -55,7 +55,7 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) { set_process(false); - track_editor->set_animation(Ref()); + track_editor->set_animation(Ref(), true); track_editor->set_root(nullptr); track_editor->show_select_node_warning(true); _update_player(); @@ -283,7 +283,28 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { Ref anim = player->get_animation(current); { - track_editor->set_animation(anim); + bool animation_library_is_foreign = false; + if (!anim->get_path().is_resource_file()) { + int srpos = anim->get_path().find("::"); + if (srpos != -1) { + String base = anim->get_path().substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + animation_library_is_foreign = true; + } + } else { + if (FileAccess::exists(base + ".import")) { + animation_library_is_foreign = true; + } + } + } + } else { + if (FileAccess::exists(anim->get_path() + ".import")) { + animation_library_is_foreign = true; + } + } + + track_editor->set_animation(anim, animation_library_is_foreign); Node *root = player->get_node(player->get_root()); if (root) { track_editor->set_root(root); @@ -292,7 +313,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) { frame->set_max((double)anim->get_length()); } else { - track_editor->set_animation(Ref()); + track_editor->set_animation(Ref(), true); track_editor->set_root(nullptr); } @@ -751,14 +772,36 @@ void AnimationPlayerEditor::_animation_edit() { String current = _get_current(); if (current != String()) { Ref anim = player->get_animation(current); - track_editor->set_animation(anim); + + bool animation_library_is_foreign = false; + if (!anim->get_path().is_resource_file()) { + int srpos = anim->get_path().find("::"); + if (srpos != -1) { + String base = anim->get_path().substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + animation_library_is_foreign = true; + } + } else { + if (FileAccess::exists(base + ".import")) { + animation_library_is_foreign = true; + } + } + } + } else { + if (FileAccess::exists(anim->get_path() + ".import")) { + animation_library_is_foreign = true; + } + } + + track_editor->set_animation(anim, animation_library_is_foreign); Node *root = player->get_node(player->get_root()); if (root) { track_editor->set_root(root); } } else { - track_editor->set_animation(Ref()); + track_editor->set_animation(Ref(), true); track_editor->set_root(nullptr); } } @@ -812,13 +855,37 @@ void AnimationPlayerEditor::_update_player() { int active_idx = -1; bool no_anims_found = true; + bool foreign_global_anim_lib = false; for (const StringName &K : libraries) { if (K != StringName()) { animation->add_separator(K); } + // Check if the global library is foreign since we want to disable options for adding/remove/renaming animations if it is. Ref library = player->get_animation_library(K); + if (K == "") { + if (!library->get_path().is_resource_file()) { + int srpos = library->get_path().find("::"); + if (srpos != -1) { + String base = library->get_path().substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + foreign_global_anim_lib = true; + } + } else { + if (FileAccess::exists(base + ".import")) { + foreign_global_anim_lib = true; + } + } + } + } else { + if (FileAccess::exists(library->get_path() + ".import")) { + foreign_global_anim_lib = true; + } + } + } + List animlist; library->get_animation_list(&animlist); @@ -835,7 +902,13 @@ void AnimationPlayerEditor::_update_player() { no_anims_found = false; } } -#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), no_anims_found) +#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), foreign_global_anim_lib) + + ITEM_CHECK_DISABLED(TOOL_NEW_ANIM); + +#undef ITEM_CHECK_DISABLED + +#define ITEM_CHECK_DISABLED(m_item) tool_anim->get_popup()->set_item_disabled(tool_anim->get_popup()->get_item_index(m_item), no_anims_found || foreign_global_anim_lib) ITEM_CHECK_DISABLED(TOOL_DUPLICATE_ANIM); ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM); @@ -877,7 +950,29 @@ void AnimationPlayerEditor::_update_player() { if (!no_anims_found) { String current = animation->get_item_text(animation->get_selected()); Ref anim = player->get_animation(current); - track_editor->set_animation(anim); + + bool animation_library_is_foreign = false; + if (!anim->get_path().is_resource_file()) { + int srpos = anim->get_path().find("::"); + if (srpos != -1) { + String base = anim->get_path().substr(0, srpos); + if (ResourceLoader::get_resource_type(base) == "PackedScene") { + if (!get_tree()->get_edited_scene_root() || get_tree()->get_edited_scene_root()->get_scene_file_path() != base) { + animation_library_is_foreign = true; + } + } else { + if (FileAccess::exists(base + ".import")) { + animation_library_is_foreign = true; + } + } + } + } else { + if (FileAccess::exists(anim->get_path() + ".import")) { + animation_library_is_foreign = true; + } + } + + track_editor->set_animation(anim, animation_library_is_foreign); Node *root = player->get_node(player->get_root()); if (root) { track_editor->set_root(root);