Merge pull request #63245 from V-Sekai/animation_editor_read_only

This commit is contained in:
Rémi Verschelde 2022-08-10 15:26:21 +02:00 committed by GitHub
commit cf95056c91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 618 additions and 319 deletions

View File

@ -328,6 +328,8 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
} }
} }
Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
Ref<Texture2D> remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")); Ref<Texture2D> remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
float remove_hpos = limit - hsep - remove->get_width(); 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; 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()); 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()); 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)) { if (locked_tracks.has(current_track)) {
@ -632,8 +638,9 @@ Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
return animation; return animation;
} }
void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) { void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
animation = p_animation; animation = p_animation;
read_only = p_read_only;
selected_track = p_track; selected_track = p_track;
update(); update();
} }
@ -715,7 +722,7 @@ void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
continue; // Skip track due to not selected. continue; // Skip track due to not selected.
} }
set_animation_and_track(animation, i); set_animation_and_track(animation, i, read_only);
break; break;
} }
} }
@ -819,12 +826,16 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) { if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) { if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) {
duplicate_selection(); if (!read_only) {
duplicate_selection();
}
accept_event(); accept_event();
} }
if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) { if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) {
delete_selection(); if (!read_only) {
delete_selection();
}
accept_event(); accept_event();
} }
} }
@ -917,26 +928,28 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) { if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
menu_insert_key = mb->get_position(); menu_insert_key = mb->get_position();
if (menu_insert_key.x >= limit && menu_insert_key.x <= get_size().width) { 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(); menu->clear();
if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) { if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT); menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
} }
if (selection.size()) { if (selection.size()) {
menu->add_separator(); menu->add_separator();
menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE); menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
menu->add_separator(); menu->add_separator();
menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE); menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
menu->add_separator(); 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("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->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
} }
if (menu->get_item_count()) { if (menu->get_item_count()) {
menu->reset_size(); menu->reset_size();
menu->set_position(popup_pos); menu->set_position(popup_pos);
menu->popup(); menu->popup();
}
} }
} }
} }
@ -945,7 +958,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (const KeyValue<int, Rect2> &E : subtracks) { for (const KeyValue<int, Rect2> &E : subtracks) {
if (E.value.has_point(mb->get_position())) { if (E.value.has_point(mb->get_position())) {
if (!locked_tracks.has(E.key) && !hidden_tracks.has(E.key)) { 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(); _clear_selection();
} }
return; return;
@ -958,30 +971,32 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (const KeyValue<int, Rect2> &I : track_icons) { for (const KeyValue<int, Rect2> &I : track_icons) {
if (I.value.has_point(mb->get_position())) { if (I.value.has_point(mb->get_position())) {
if (I.key == REMOVE_ICON) { 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_locked_tracks_after", track);
undo_redo->add_do_method(this, "_update_hidden_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(), "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(), "track_set_path", track, animation->track_get_path(track));
for (int i = 0; i < animation->track_get_key_count(track); ++i) { for (int i = 0; i < animation->track_get_key_count(track); ++i) {
undo_redo->add_undo_method( undo_redo->add_undo_method(
animation.ptr(), animation.ptr(),
"bezier_track_insert_key", "bezier_track_insert_key",
track, animation->track_get_key_time(track, i), track, animation->track_get_key_time(track, i),
animation->bezier_track_get_key_value(track, i), animation->bezier_track_get_key_value(track, i),
animation->bezier_track_get_key_in_handle(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_out_handle(track, i),
animation->bezier_track_get_key_handle_mode(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; return;
} else if (I.key == LOCK_ICON) { } else if (I.key == LOCK_ICON) {
if (locked_tracks.has(track)) { if (locked_tracks.has(track)) {
@ -991,7 +1006,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (selected_track == track) { if (selected_track == track) {
for (int i = 0; i < animation->get_track_count(); ++i) { for (int i = 0; i < animation->get_track_count(); ++i) {
if (!locked_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) { 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; break;
} }
} }
@ -1007,7 +1022,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (selected_track == track) { if (selected_track == track) {
for (int i = 0; i < animation->get_track_count(); ++i) { for (int i = 0; i < animation->get_track_count(); ++i) {
if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) { 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; break;
} }
} }
@ -1046,7 +1061,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
} }
} }
set_animation_and_track(animation, track); set_animation_and_track(animation, track, read_only);
solo_track = track; solo_track = track;
} }
update(); update();
@ -1087,7 +1102,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_from_key = pair.second; moving_selection_from_key = pair.second;
moving_selection_from_track = pair.first; moving_selection_from_track = pair.first;
moving_selection_offset = Vector2(); moving_selection_offset = Vector2();
set_animation_and_track(animation, pair.first); set_animation_and_track(animation, pair.first, read_only);
selection.clear(); selection.clear();
selection.insert(pair); selection.insert(pair);
update(); update();
@ -1096,24 +1111,26 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
} }
} }
if (edit_points[i].in_rect.has_point(mb->get_position())) { if (!read_only) {
moving_handle = -1; if (edit_points[i].in_rect.has_point(mb->get_position())) {
moving_handle_key = edit_points[i].key; moving_handle = -1;
moving_handle_track = edit_points[i].track; moving_handle_key = edit_points[i].key;
moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key); moving_handle_track = edit_points[i].track;
moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key); moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
update(); moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
return; update();
} return;
}
if (edit_points[i].out_rect.has_point(mb->get_position())) { if (edit_points[i].out_rect.has_point(mb->get_position())) {
moving_handle = 1; moving_handle = 1;
moving_handle_key = edit_points[i].key; moving_handle_key = edit_points[i].key;
moving_handle_track = edit_points[i].track; 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_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); moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
update(); update();
return; return;
}
} }
} }
@ -1191,7 +1208,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
selection.insert(IntPair(edit_points[i].track, edit_points[i].key)); selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
if (!track_set) { if (!track_set) {
track_set = true; 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<InputEvent> &p_event) {
float track_height = _bezier_h_to_pixel(track_h); float track_height = _bezier_h_to_pixel(track_h);
if (abs(mb->get_position().y - track_height) < 10) { if (abs(mb->get_position().y - track_height) < 10) {
set_animation_and_track(animation, i); set_animation_and_track(animation, i, read_only);
break; break;
} }
} }
@ -1229,102 +1246,106 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
} }
if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
undo_redo->create_action(TTR("Move Bezier Points")); if (!read_only) {
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left); undo_redo->create_action(TTR("Move Bezier Points"));
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", selected_track, moving_handle_key, moving_handle_right); undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", selected_track, moving_handle_key, moving_handle_left);
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_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_out_handle", selected_track, moving_handle_key, animation->bezier_track_get_key_out_handle(selected_track, moving_handle_key)); 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->commit_action(); 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; moving_handle = 0;
update(); update();
}
} }
if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (moving_selection) { if (!read_only) {
//combit it if (moving_selection) {
//combit it
undo_redo->create_action(TTR("Move Bezier Points")); undo_redo->create_action(TTR("Move Bezier Points"));
List<AnimMoveRestore> to_restore; List<AnimMoveRestore> to_restore;
// 1-remove the keys // 1-remove the keys
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { 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); undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
} }
// 2- remove overlapped keys // 2- remove overlapped keys
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { 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); 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); int idx = animation->track_find_key(E->get().first, newtime, true);
if (idx == -1) { if (idx == -1) {
continue; 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))) { // 3-move the keys (re insert them)
continue; //already in selection, don't save 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); // 4-(undo) remove inserted keys
AnimMoveRestore amr; 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); // 5-(undo) reinsert keys
amr.track = E->get().first; for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
amr.time = newtime; 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) moving_selection_attempt = false;
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { update();
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();
} }
Ref<InputEventMouseMotion> mm = p_event; Ref<InputEventMouseMotion> mm = p_event;
@ -1337,7 +1358,9 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
float y = (get_size().height / 2 - mm->get_position().y) * v_zoom + v_scroll; 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()); 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(); update();
} }
@ -1399,20 +1422,22 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
bool is_finishing_key_handle_drag = moving_handle != 0 && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT; 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) { if (is_finishing_key_handle_drag) {
undo_redo->create_action(TTR("Move Bezier Points")); if (!read_only) {
if (moving_handle == -1) { undo_redo->create_action(TTR("Move Bezier Points"));
double ratio = timeline->get_zoom_scale() * v_zoom; if (moving_handle == -1) {
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio); double ratio = timeline->get_zoom_scale() * v_zoom;
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); undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
} else if (moving_handle == 1) { 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);
double ratio = timeline->get_zoom_scale() * v_zoom; } else if (moving_handle == 1) {
undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio); double ratio = timeline->get_zoom_scale() * v_zoom;
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->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(); }
undo_redo->commit_action();
moving_handle = 0; moving_handle = 0;
update(); update();
}
} }
} }

View File

@ -54,6 +54,7 @@ class AnimationBezierTrackEdit : public Control {
float play_position_pos = 0; float play_position_pos = 0;
Ref<Animation> animation; Ref<Animation> animation;
bool read_only = false;
int selected_track = 0; int selected_track = 0;
Vector<Rect2> view_rects; Vector<Rect2> view_rects;
@ -176,7 +177,7 @@ public:
Ref<Animation> get_animation() const; Ref<Animation> get_animation() const;
void set_animation_and_track(const Ref<Animation> &p_animation, int p_track); void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override; virtual Size2 get_minimum_size() const override;
void set_undo_redo(UndoRedo *p_undo_redo); void set_undo_redo(UndoRedo *p_undo_redo);

View File

@ -48,6 +48,7 @@ class AnimationTrackKeyEdit : public Object {
public: public:
bool setting = false; bool setting = false;
bool animation_read_only = false;
bool _hide_script_from_inspector() { bool _hide_script_from_inspector() {
return true; return true;
@ -57,12 +58,17 @@ public:
return true; return true;
} }
bool _read_only() {
return animation_read_only;
}
static void _bind_methods() { static void _bind_methods() {
ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj); ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj);
ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed); 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("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector);
ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path); ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path);
ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo); ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo);
ClassDB::bind_method("_read_only", &AnimationTrackKeyEdit::_read_only);
} }
void _fix_node_path(Variant &value) { void _fix_node_path(Variant &value) {
@ -703,6 +709,7 @@ class AnimationMultiTrackKeyEdit : public Object {
public: public:
bool setting = false; bool setting = false;
bool animation_read_only = false;
bool _hide_script_from_inspector() { bool _hide_script_from_inspector() {
return true; return true;
@ -712,12 +719,17 @@ public:
return true; return true;
} }
bool _read_only() {
return animation_read_only;
}
static void _bind_methods() { static void _bind_methods() {
ClassDB::bind_method("_update_obj", &AnimationMultiTrackKeyEdit::_update_obj); ClassDB::bind_method("_update_obj", &AnimationMultiTrackKeyEdit::_update_obj);
ClassDB::bind_method("_key_ofs_changed", &AnimationMultiTrackKeyEdit::_key_ofs_changed); 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("_hide_script_from_inspector", &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
ClassDB::bind_method("get_root_path", &AnimationMultiTrackKeyEdit::get_root_path); ClassDB::bind_method("get_root_path", &AnimationMultiTrackKeyEdit::get_root_path);
ClassDB::bind_method("_dont_undo_redo", &AnimationMultiTrackKeyEdit::_dont_undo_redo); 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) { void _fix_node_path(Variant &value, NodePath &base) {
@ -1416,22 +1428,32 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
} }
void AnimationTimelineEdit::_anim_loop_pressed() { void AnimationTimelineEdit::_anim_loop_pressed() {
undo_redo->create_action(TTR("Change Animation Loop")); if (!read_only) {
switch (animation->get_loop_mode()) { undo_redo->create_action(TTR("Change Animation Loop"));
case Animation::LOOP_NONE: { switch (animation->get_loop_mode()) {
undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR); case Animation::LOOP_NONE: {
} break; undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_LINEAR);
case Animation::LOOP_LINEAR: { } break;
undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG); case Animation::LOOP_LINEAR: {
} break; undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_PINGPONG);
case Animation::LOOP_PINGPONG: { } break;
undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE); case Animation::LOOP_PINGPONG: {
} break; undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LOOP_NONE);
default: } break;
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 { int AnimationTimelineEdit::get_buttons_width() const {
@ -1656,11 +1678,17 @@ void AnimationTimelineEdit::_notification(int p_what) {
} }
} }
void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation) { void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation, bool p_read_only) {
animation = p_animation; animation = p_animation;
read_only = p_read_only;
if (animation.is_valid()) { if (animation.is_valid()) {
len_hb->show(); len_hb->show();
add_track->show(); if (read_only) {
add_track->hide();
} else {
add_track->show();
}
play_position->show(); play_position->show();
} else { } else {
len_hb->hide(); len_hb->hide();
@ -1982,6 +2010,8 @@ void AnimationTrackEdit::_notification(int p_what) {
Color linecolor = color; Color linecolor = color;
linecolor.a = 0.2; linecolor.a = 0.2;
Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
// NAMES AND ICONS // // NAMES AND ICONS //
{ {
@ -2131,14 +2161,18 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += update_icon->get_width() + hsep / 2; ofs += update_icon->get_width() + hsep / 2;
update_mode_rect.size.x += hsep / 2; update_mode_rect.size.x += hsep / 2;
if (animation->track_get_type(track) == Animation::TYPE_VALUE) { if (!read_only) {
draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2)); if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
update_mode_rect.size.x += down_icon->get_width(); draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
} else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) { update_mode_rect.size.x += down_icon->get_width();
Ref<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")); } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
update_mode_rect.size.x += down_icon->get_width(); Ref<Texture2D> 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 { } else {
update_mode_rect = Rect2(); update_mode_rect = Rect2();
} }
@ -2169,7 +2203,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep / 2; ofs += icon->get_width() + hsep / 2;
interp_mode_rect.size.x += 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)); draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
interp_mode_rect.size.x += down_icon->get_width(); interp_mode_rect.size.x += down_icon->get_width();
} else { } else {
@ -2202,7 +2236,7 @@ void AnimationTrackEdit::_notification(int p_what) {
ofs += icon->get_width() + hsep / 2; ofs += icon->get_width() + hsep / 2;
loop_wrap_rect.size.x += 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)); draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
loop_wrap_rect.size.x += down_icon->get_width(); loop_wrap_rect.size.x += down_icon->get_width();
} else { } else {
@ -2223,7 +2257,11 @@ void AnimationTrackEdit::_notification(int p_what) {
remove_rect.position.y = int(get_size().height - icon->get_height()) / 2; remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
remove_rect.size = icon->get_size(); 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);
}
} }
} }
@ -2439,8 +2477,10 @@ Ref<Animation> AnimationTrackEdit::get_animation() const {
return animation; return animation;
} }
void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) { void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
animation = p_animation; animation = p_animation;
read_only = p_read_only;
track = p_track; track = p_track;
update(); update();
@ -2721,17 +2761,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (p_event->is_pressed()) { if (p_event->is_pressed()) {
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) { 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(); accept_event();
} }
if (ED_GET_SHORTCUT("animation_editor/duplicate_selection_transposed")->matches_event(p_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(); accept_event();
} }
if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_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(); accept_event();
} }
} }
@ -2740,79 +2786,81 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) { if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Point2 pos = mb->get_position(); Point2 pos = mb->get_position();
if (check_rect.has_point(pos)) { if (!read_only) {
undo_redo->create_action(TTR("Toggle Track Enabled")); if (check_rect.has_point(pos)) {
undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track)); undo_redo->create_action(TTR("Toggle Track Enabled"));
undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track)); undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
undo_redo->commit_action(); undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
update(); undo_redo->commit_action();
accept_event(); 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));
} }
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); // Don't overlap track keys if they start at 0.
menu->set_position(popup_pos); if (path_rect.has_point(pos + Size2(type_icon->get_width(), 0))) {
menu->popup(); clicking_on_name = true;
accept_event(); 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();
Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height); if (update_mode_rect.has_point(pos)) {
menu->set_position(popup_pos); if (!menu) {
menu->popup(); menu = memnew(PopupMenu);
accept_event(); 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)) { Vector2 popup_pos = get_screen_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
if (!menu) { menu->set_position(popup_pos);
menu = memnew(PopupMenu); menu->popup();
add_child(menu); accept_event();
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); if (interp_mode_rect.has_point(pos)) {
menu->set_position(popup_pos); if (!menu) {
menu->popup(); menu = memnew(PopupMenu);
accept_event(); 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)) { Vector2 popup_pos = get_screen_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
emit_signal(SNAME("remove_request"), track); menu->set_position(popup_pos);
accept_event(); menu->popup();
return; 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. // Check keyframes.
@ -2872,6 +2920,11 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
moving_selection_attempt = true; moving_selection_attempt = true;
moving_selection_from_ofs = (mb->get_position().x - limit) / timeline->get_zoom_scale(); 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(); accept_event();
} }
} }
@ -2883,33 +2936,35 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) { 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. // Can do something with menu too! show insert key.
float offset = (pos.x - timeline->get_name_limit()) / timeline->get_zoom_scale(); float offset = (pos.x - timeline->get_name_limit()) / timeline->get_zoom_scale();
if (!menu) { if (!read_only) {
menu = memnew(PopupMenu); if (!menu) {
add_child(menu); menu = memnew(PopupMenu);
menu->connect("id_pressed", callable_mp(this, &AnimationTrackEdit::_menu_selected)); 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);
} }
menu->add_separator(); menu->clear();
menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Key(s)"), MENU_KEY_DELETE); 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();
} }
} }
@ -3354,7 +3409,7 @@ void AnimationTrackEditor::remove_track_edit_plugin(const Ref<AnimationTrackEdit
track_edit_plugins.erase(p_plugin); track_edit_plugins.erase(p_plugin);
} }
void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) { void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim, bool p_read_only) {
if (animation != p_anim && _get_track_selected() >= 0) { if (animation != p_anim && _get_track_selected() >= 0) {
track_edits[_get_track_selected()]->release_focus(); track_edits[_get_track_selected()]->release_focus();
} }
@ -3363,7 +3418,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
_clear_selection(); _clear_selection();
} }
animation = p_anim; animation = p_anim;
timeline->set_animation(p_anim); read_only = p_read_only;
timeline->set_animation(p_anim, read_only);
_cancel_bezier_edit(); _cancel_bezier_edit();
_update_tracks(); _update_tracks();
@ -3372,7 +3428,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed)); animation->connect("changed", callable_mp(this, &AnimationTrackEditor::_animation_changed));
hscroll->show(); hscroll->show();
edit->set_disabled(false); edit->set_disabled(read_only);
step->set_block_signals(true); step->set_block_signals(true);
_update_step_spinbox(); _update_step_spinbox();
@ -3501,7 +3557,7 @@ void AnimationTrackEditor::set_state(const Dictionary &p_state) {
} }
void AnimationTrackEditor::cleanup() { void AnimationTrackEditor::cleanup() {
set_animation(Ref<Animation>()); set_animation(Ref<Animation>(), read_only);
} }
void AnimationTrackEditor::_name_limit_changed() { void AnimationTrackEditor::_name_limit_changed() {
@ -4378,6 +4434,27 @@ void AnimationTrackEditor::_update_tracks() {
return; 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<String, VBoxContainer *> group_sort; RBMap<String, VBoxContainer *> group_sort;
bool use_grouping = !view_group->is_pressed(); bool use_grouping = !view_group->is_pressed();
@ -4506,7 +4583,7 @@ void AnimationTrackEditor::_update_tracks() {
track_edit->set_undo_redo(undo_redo); track_edit->set_undo_redo(undo_redo);
track_edit->set_timeline(timeline); track_edit->set_timeline(timeline);
track_edit->set_root(root); 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_play_position(timeline->get_play_position());
track_edit->set_editor(this); track_edit->set_editor(this);
@ -5178,6 +5255,7 @@ void AnimationTrackEditor::_update_key_edit() {
if (selection.size() == 1) { if (selection.size() == 1) {
key_edit = memnew(AnimationTrackKeyEdit); key_edit = memnew(AnimationTrackKeyEdit);
key_edit->animation = animation; key_edit->animation = animation;
key_edit->animation_read_only = read_only;
key_edit->track = selection.front()->key().track; key_edit->track = selection.front()->key().track;
key_edit->use_fps = timeline->is_using_fps(); key_edit->use_fps = timeline->is_using_fps();
@ -5194,6 +5272,7 @@ void AnimationTrackEditor::_update_key_edit() {
} else if (selection.size() > 1) { } else if (selection.size() > 1) {
multi_key_edit = memnew(AnimationMultiTrackKeyEdit); multi_key_edit = memnew(AnimationMultiTrackKeyEdit);
multi_key_edit->animation = animation; multi_key_edit->animation = animation;
multi_key_edit->animation_read_only = read_only;
RBMap<int, List<float>> key_ofs_map; RBMap<int, List<float>> key_ofs_map;
RBMap<int, NodePath> base_map; RBMap<int, NodePath> base_map;
@ -5473,7 +5552,7 @@ void AnimationTrackEditor::_cancel_bezier_edit() {
void AnimationTrackEditor::_bezier_edit(int p_for_track) { void AnimationTrackEditor::_bezier_edit(int p_for_track) {
_clear_selection(); // Bezier probably wants to use a separate selection mode. _clear_selection(); // Bezier probably wants to use a separate selection mode.
bezier_edit->set_root(root); 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(); scroll->hide();
bezier_edit->show(); bezier_edit->show();
// Search everything within the track and curve - edit it. // Search everything within the track and curve - edit it.

View File

@ -56,6 +56,8 @@ class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range); GDCLASS(AnimationTimelineEdit, Range);
Ref<Animation> animation; Ref<Animation> animation;
bool read_only = false;
AnimationTrackEdit *track_edit = nullptr; AnimationTrackEdit *track_edit = nullptr;
int name_limit = 0; int name_limit = 0;
Range *zoom = nullptr; Range *zoom = nullptr;
@ -106,7 +108,7 @@ public:
float get_zoom_scale() const; float get_zoom_scale() const;
virtual Size2 get_minimum_size() const override; virtual Size2 get_minimum_size() const override;
void set_animation(const Ref<Animation> &p_animation); void set_animation(const Ref<Animation> &p_animation, bool p_read_only);
void set_track_edit(AnimationTrackEdit *p_track_edit); void set_track_edit(AnimationTrackEdit *p_track_edit);
void set_zoom(Range *p_zoom); void set_zoom(Range *p_zoom);
Range *get_zoom() const { return zoom; } Range *get_zoom() const { return zoom; }
@ -159,6 +161,7 @@ class AnimationTrackEdit : public Control {
NodePath node_path; NodePath node_path;
Ref<Animation> animation; Ref<Animation> animation;
bool read_only = false;
int track = 0; int track = 0;
Rect2 check_rect; Rect2 check_rect;
@ -232,7 +235,7 @@ public:
AnimationTrackEditor *get_editor() const { return editor; } AnimationTrackEditor *get_editor() const { return editor; }
UndoRedo *get_undo_redo() const { return undo_redo; } UndoRedo *get_undo_redo() const { return undo_redo; }
NodePath get_path() const; NodePath get_path() const;
void set_animation_and_track(const Ref<Animation> &p_animation, int p_track); void set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only);
virtual Size2 get_minimum_size() const override; virtual Size2 get_minimum_size() const override;
void set_undo_redo(UndoRedo *p_undo_redo); void set_undo_redo(UndoRedo *p_undo_redo);
@ -290,6 +293,7 @@ class AnimationTrackEditor : public VBoxContainer {
GDCLASS(AnimationTrackEditor, VBoxContainer); GDCLASS(AnimationTrackEditor, VBoxContainer);
Ref<Animation> animation; Ref<Animation> animation;
bool read_only = false;
Node *root = nullptr; Node *root = nullptr;
MenuButton *edit = nullptr; MenuButton *edit = nullptr;
@ -533,7 +537,7 @@ public:
void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin); void add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin); void remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin);
void set_animation(const Ref<Animation> &p_anim); void set_animation(const Ref<Animation> &p_anim, bool p_read_only);
Ref<Animation> get_current_animation() const; Ref<Animation> get_current_animation() const;
void set_root(Node *p_root); void set_root(Node *p_root);
Node *get_root() const; Node *get_root() const;

View File

@ -149,13 +149,35 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
} }
switch (p_id) { switch (p_id) {
case FILE_MENU_SAVE_LIBRARY: { 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); EditorNode::get_singleton()->save_resource(al);
break; break;
} }
[[fallthrough]]; [[fallthrough]];
} }
case FILE_MENU_SAVE_AS_LIBRARY: { 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_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Library")); file_dialog->set_title(TTR("Save Library"));
if (al->get_path().is_resource_file()) { if (al->get_path().is_resource_file()) {
@ -178,6 +200,9 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
Ref<AnimationLibrary> ald = al->duplicate(); Ref<AnimationLibrary> 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(); UndoRedo *undo_redo = EditorNode::get_singleton()->get_undo_redo();
undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name)); undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", 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->add_undo_method(this, "_update_editor", player);
undo_redo->commit_action(); undo_redo->commit_action();
update_tree();
} break; } break;
case FILE_MENU_EDIT_LIBRARY: { case FILE_MENU_EDIT_LIBRARY: {
EditorNode::get_singleton()->push_item(al.ptr()); EditorNode::get_singleton()->push_item(al.ptr());
} break; } break;
case FILE_MENU_SAVE_ANIMATION: { 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); EditorNode::get_singleton()->save_resource(anim);
break; break;
} }
[[fallthrough]]; [[fallthrough]];
} }
case FILE_MENU_SAVE_AS_ANIMATION: { 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_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE);
file_dialog->set_title(TTR("Save Animation")); file_dialog->set_title(TTR("Save Animation"));
if (anim->get_path().is_resource_file()) { 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_do_method(this, "_update_editor", player);
undo_redo->add_undo_method(this, "_update_editor", player); undo_redo->add_undo_method(this, "_update_editor", player);
undo_redo->commit_action(); undo_redo->commit_action();
update_tree();
} break; } break;
case FILE_MENU_EDIT_ANIMATION: { case FILE_MENU_EDIT_ANIMATION: {
EditorNode::get_singleton()->push_item(anim.ptr()); EditorNode::get_singleton()->push_item(anim.ptr());
@ -577,19 +628,45 @@ void AnimationLibraryEditor::update_tree() {
} else { } else {
libitem->set_suffix(0, ""); libitem->set_suffix(0, "");
} }
libitem->set_editable(0, true);
Ref<AnimationLibrary> 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_metadata(0, K);
libitem->set_icon(0, get_theme_icon("AnimationLibrary", "EditorIcons")); 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("Add", "EditorIcons"), LIB_BUTTON_ADD, animation_library_is_foreign, TTR("Add Animation to Library"));
libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, false, TTR("Paste Animation to Library from clipboard")); 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"));
Ref<AnimationLibrary> al = player->call("get_animation_library", K); libitem->add_button(0, get_theme_icon("ActionPaste", "EditorIcons"), LIB_BUTTON_PASTE, animation_library_is_foreign, TTR("Paste Animation to Library from clipboard"));
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(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("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")); 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) { for (const StringName &L : animations) {
TreeItem *anitem = tree->create_item(libitem); TreeItem *anitem = tree->create_item(libitem);
anitem->set_text(0, L); 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_metadata(0, L);
anitem->set_icon(0, get_theme_icon("Animation", "EditorIcons")); 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")); anitem->add_button(0, get_theme_icon("ActionCopy", "EditorIcons"), ANIM_BUTTON_COPY, animation_library_is_foreign, TTR("Copy animation to clipboard"));
Ref<Animation> anim = al->get_animation(L);
if (anim->get_path().is_resource_file()) { Ref<Animation> anim = al->get_animation(L);
anitem->set_text(1, anim->get_path().get_file()); String anim_path = anim->get_path();
anitem->set_tooltip(1, anim->get_path()); if (!anim_path.is_resource_file()) {
} else {
anitem->set_text(1, TTR("[built-in]")); 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("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, false, TTR("Remove animation from Library")); anitem->add_button(1, get_theme_icon("Remove", "EditorIcons"), ANIM_BUTTON_DELETE, animation_library_is_foreign, TTR("Remove animation from Library"));
} }
} }
} }

View File

@ -55,7 +55,7 @@ void AnimationPlayerEditor::_node_removed(Node *p_node) {
set_process(false); set_process(false);
track_editor->set_animation(Ref<Animation>()); track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr); track_editor->set_root(nullptr);
track_editor->show_select_node_warning(true); track_editor->show_select_node_warning(true);
_update_player(); _update_player();
@ -283,7 +283,28 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
Ref<Animation> anim = player->get_animation(current); Ref<Animation> 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()); Node *root = player->get_node(player->get_root());
if (root) { if (root) {
track_editor->set_root(root); track_editor->set_root(root);
@ -292,7 +313,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
frame->set_max((double)anim->get_length()); frame->set_max((double)anim->get_length());
} else { } else {
track_editor->set_animation(Ref<Animation>()); track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr); track_editor->set_root(nullptr);
} }
@ -751,14 +772,36 @@ void AnimationPlayerEditor::_animation_edit() {
String current = _get_current(); String current = _get_current();
if (current != String()) { if (current != String()) {
Ref<Animation> anim = player->get_animation(current); Ref<Animation> 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()); Node *root = player->get_node(player->get_root());
if (root) { if (root) {
track_editor->set_root(root); track_editor->set_root(root);
} }
} else { } else {
track_editor->set_animation(Ref<Animation>()); track_editor->set_animation(Ref<Animation>(), true);
track_editor->set_root(nullptr); track_editor->set_root(nullptr);
} }
} }
@ -812,13 +855,37 @@ void AnimationPlayerEditor::_update_player() {
int active_idx = -1; int active_idx = -1;
bool no_anims_found = true; bool no_anims_found = true;
bool foreign_global_anim_lib = false;
for (const StringName &K : libraries) { for (const StringName &K : libraries) {
if (K != StringName()) { if (K != StringName()) {
animation->add_separator(K); 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<AnimationLibrary> library = player->get_animation_library(K); Ref<AnimationLibrary> 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<StringName> animlist; List<StringName> animlist;
library->get_animation_list(&animlist); library->get_animation_list(&animlist);
@ -835,7 +902,13 @@ void AnimationPlayerEditor::_update_player() {
no_anims_found = false; 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_DUPLICATE_ANIM);
ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM); ITEM_CHECK_DISABLED(TOOL_RENAME_ANIM);
@ -877,7 +950,29 @@ void AnimationPlayerEditor::_update_player() {
if (!no_anims_found) { if (!no_anims_found) {
String current = animation->get_item_text(animation->get_selected()); String current = animation->get_item_text(animation->get_selected());
Ref<Animation> anim = player->get_animation(current); Ref<Animation> 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()); Node *root = player->get_node(player->get_root());
if (root) { if (root) {
track_editor->set_root(root); track_editor->set_root(root);