summaryrefslogtreecommitdiff
path: root/editor/animation_track_editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/animation_track_editor.cpp')
-rw-r--r--editor/animation_track_editor.cpp1795
1 files changed, 998 insertions, 797 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 961eb907bb..0db82551cb 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -37,6 +37,7 @@
#include "editor/editor_scale.h"
#include "editor/plugins/animation_player_editor_plugin.h"
#include "scene/animation/animation_player.h"
+#include "scene/gui/separator.h"
#include "scene/gui/view_panner.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -47,6 +48,7 @@ class AnimationTrackKeyEdit : public Object {
public:
bool setting = false;
+ bool animation_read_only = false;
bool _hide_script_from_inspector() {
return true;
@@ -56,12 +58,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) {
@@ -358,7 +365,7 @@ public:
setting = true;
undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
- RES prev = animation->audio_track_get_key_stream(track, key);
+ Ref<Resource> prev = animation->audio_track_get_key_stream(track, key);
undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
undo_redo->add_do_method(this, "_update_obj", animation);
@@ -560,54 +567,53 @@ public:
if (use_fps && animation->get_step() > 0) {
float max_frame = animation->get_length() / animation->get_step();
- p_list->push_back(PropertyInfo(Variant::FLOAT, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("frame"), PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
} else {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("time"), PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
}
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "position"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position")));
} break;
case Animation::TYPE_ROTATION_3D: {
- p_list->push_back(PropertyInfo(Variant::QUATERNION, "rotation"));
+ p_list->push_back(PropertyInfo(Variant::QUATERNION, PNAME("rotation")));
} break;
case Animation::TYPE_SCALE_3D: {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("scale")));
} break;
case Animation::TYPE_BLEND_SHAPE: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
} break;
case Animation::TYPE_VALUE: {
Variant v = animation->track_get_key_value(track, key);
if (hint.type != Variant::NIL) {
PropertyInfo pi = hint;
- pi.name = "value";
+ pi.name = PNAME("value");
p_list->push_back(pi);
} else {
- PropertyHint hint = PROPERTY_HINT_NONE;
- String hint_string;
+ PropertyHint val_hint = PROPERTY_HINT_NONE;
+ String val_hint_string;
if (v.get_type() == Variant::OBJECT) {
// Could actually check the object property if exists..? Yes I will!
Ref<Resource> res = v;
if (res.is_valid()) {
- hint = PROPERTY_HINT_RESOURCE_TYPE;
- hint_string = res->get_class();
+ val_hint = PROPERTY_HINT_RESOURCE_TYPE;
+ val_hint_string = res->get_class();
}
}
if (v.get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(v.get_type(), "value", hint, hint_string));
+ p_list->push_back(PropertyInfo(v.get_type(), PNAME("value"), val_hint, val_hint_string));
}
}
} break;
case Animation::TYPE_METHOD: {
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name"));
- static_assert(VARIANT_ARG_MAX == 8, "PROPERTY_HINT_RANGE needs to be updated if VARIANT_ARG_MAX != 8");
- p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,8,1"));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("name")));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("arg_count"), PROPERTY_HINT_RANGE, "0,32,1,or_greater"));
Dictionary d = animation->track_get_key_value(track, key);
ERR_FAIL_COND(!d.has("args"));
@@ -621,24 +627,24 @@ public:
}
for (int i = 0; i < args.size(); i++) {
- p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes));
+ p_list->push_back(PropertyInfo(Variant::INT, vformat("%s/%d/%s", PNAME("args"), i, PNAME("type")), PROPERTY_HINT_ENUM, vtypes));
if (args[i].get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value"));
+ p_list->push_back(PropertyInfo(args[i].get_type(), vformat("%s/%d/%s", PNAME("args"), i, PNAME("value"))));
}
}
} break;
case Animation::TYPE_BEZIER: {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "value"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
- p_list->push_back(PropertyInfo(Variant::INT, "handle_mode", PROPERTY_HINT_ENUM, "Free,Balanced"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("value")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("in_handle")));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2, PNAME("out_handle")));
+ p_list->push_back(PropertyInfo(Variant::INT, PNAME("handle_mode"), PROPERTY_HINT_ENUM, "Free,Balanced"));
} break;
case Animation::TYPE_AUDIO: {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("stream"), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("start_offset"), PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("end_offset"), PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
} break;
case Animation::TYPE_ANIMATION: {
@@ -664,13 +670,13 @@ public:
}
animations += "[stop]";
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "animation", PROPERTY_HINT_ENUM, animations));
+ p_list->push_back(PropertyInfo(Variant::STRING_NAME, PNAME("animation"), PROPERTY_HINT_ENUM, animations));
} break;
}
if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "easing", PROPERTY_HINT_EXP_EASING));
+ p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING));
}
}
@@ -703,6 +709,7 @@ class AnimationMultiTrackKeyEdit : public Object {
public:
bool setting = false;
+ bool animation_read_only = false;
bool _hide_script_from_inspector() {
return true;
@@ -712,12 +719,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) {
@@ -993,7 +1005,7 @@ public:
setting = true;
undo_redo->create_action(TTR("Anim Multi Change Keyframe Value"), UndoRedo::MERGE_ENDS);
}
- RES prev = animation->audio_track_get_key_stream(track, key);
+ Ref<Resource> prev = animation->audio_track_get_key_stream(track, key);
undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
update_obj = true;
@@ -1265,20 +1277,20 @@ public:
pi.name = "value";
p_list->push_back(pi);
} else {
- PropertyHint hint = PROPERTY_HINT_NONE;
- String hint_string;
+ PropertyHint val_hint = PROPERTY_HINT_NONE;
+ String val_hint_string;
if (v.get_type() == Variant::OBJECT) {
// Could actually check the object property if exists..? Yes I will!
Ref<Resource> res = v;
if (res.is_valid()) {
- hint = PROPERTY_HINT_RESOURCE_TYPE;
- hint_string = res->get_class();
+ val_hint = PROPERTY_HINT_RESOURCE_TYPE;
+ val_hint_string = res->get_class();
}
}
if (v.get_type() != Variant::NIL) {
- p_list->push_back(PropertyInfo(v.get_type(), "value", hint, hint_string));
+ p_list->push_back(PropertyInfo(v.get_type(), "value", val_hint, val_hint_string));
}
}
}
@@ -1287,8 +1299,8 @@ public:
} break;
case Animation::TYPE_METHOD: {
p_list->push_back(PropertyInfo(Variant::STRING_NAME, "name"));
- static_assert(VARIANT_ARG_MAX == 8, "PROPERTY_HINT_RANGE needs to be updated if VARIANT_ARG_MAX != 8");
- p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,8,1"));
+
+ p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,32,1,or_greater"));
Dictionary d = animation->track_get_key_value(first_track, first_key);
ERR_FAIL_COND(!d.has("args"));
@@ -1354,8 +1366,8 @@ public:
Ref<Animation> animation;
- Map<int, List<float>> key_ofs_map;
- Map<int, NodePath> base_map;
+ RBMap<int, List<float>> key_ofs_map;
+ RBMap<int, NodePath> base_map;
PropertyInfo hint;
Node *root_path = nullptr;
@@ -1416,22 +1428,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::LoopMode::LOOP_NONE: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_LINEAR);
- } break;
- case Animation::LoopMode::LOOP_LINEAR: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::LOOP_PINGPONG);
- } break;
- case Animation::LoopMode::LOOP_PINGPONG: {
- undo_redo->add_do_method(animation.ptr(), "set_loop_mode", Animation::LoopMode::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 {
@@ -1458,206 +1480,215 @@ int AnimationTimelineEdit::get_name_limit() const {
}
void AnimationTimelineEdit::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- }
-
- if (p_what == NOTIFICATION_ENTER_TREE) {
- add_track->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
- loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons")));
- time_icon->set_texture(get_theme_icon(SNAME("Time"), SNAME("EditorIcons")));
-
- add_track->get_popup()->clear();
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")), TTR("Property Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXPosition"), SNAME("EditorIcons")), TTR("3D Position Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXRotation"), SNAME("EditorIcons")), TTR("3D Rotation Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXScale"), SNAME("EditorIcons")), TTR("3D Scale Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyBlendShape"), SNAME("EditorIcons")), TTR("Blend Shape Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")), TTR("Call Method Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")), TTR("Bezier Curve Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")), TTR("Audio Playback Track"));
- add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyAnimation"), SNAME("EditorIcons")), TTR("Animation Playback Track"));
- }
+ switch (p_what) {
+ case NOTIFICATION_ENTER_TREE:
+ case NOTIFICATION_THEME_CHANGED: {
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ add_track->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
+ loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons")));
+ time_icon->set_texture(get_theme_icon(SNAME("Time"), SNAME("EditorIcons")));
+
+ add_track->get_popup()->clear();
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")), TTR("Property Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXPosition"), SNAME("EditorIcons")), TTR("3D Position Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXRotation"), SNAME("EditorIcons")), TTR("3D Rotation Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyXScale"), SNAME("EditorIcons")), TTR("3D Scale Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyBlendShape"), SNAME("EditorIcons")), TTR("Blend Shape Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")), TTR("Call Method Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")), TTR("Bezier Curve Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")), TTR("Audio Playback Track"));
+ add_track->get_popup()->add_icon_item(get_theme_icon(SNAME("KeyAnimation"), SNAME("EditorIcons")), TTR("Animation Playback Track"));
+ } break;
- if (p_what == NOTIFICATION_RESIZED) {
- len_hb->set_position(Vector2(get_size().width - get_buttons_width(), 0));
- len_hb->set_size(Size2(get_buttons_width(), get_size().height));
- }
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ } break;
- if (p_what == NOTIFICATION_DRAW) {
- int key_range = get_size().width - get_buttons_width() - get_name_limit();
+ case NOTIFICATION_RESIZED: {
+ len_hb->set_position(Vector2(get_size().width - get_buttons_width(), 0));
+ len_hb->set_size(Size2(get_buttons_width(), get_size().height));
+ } break;
- if (!animation.is_valid()) {
- return;
- }
+ case NOTIFICATION_DRAW: {
+ int key_range = get_size().width - get_buttons_width() - get_name_limit();
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
+ if (!animation.is_valid()) {
+ return;
+ }
- int zoomw = key_range;
- float scale = get_zoom_scale();
- int h = get_size().height;
+ Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
+ int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
+ Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
- float l = animation->get_length();
- if (l <= 0) {
- l = 0.001; // Avoid crashor.
- }
+ int zoomw = key_range;
+ float scale = get_zoom_scale();
+ int h = get_size().height;
- Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons"));
- hsize_rect = Rect2(get_name_limit() - hsize_icon->get_width() - 2 * EDSCALE, (get_size().height - hsize_icon->get_height()) / 2, hsize_icon->get_width(), hsize_icon->get_height());
- draw_texture(hsize_icon, hsize_rect.position);
+ float l = animation->get_length();
+ if (l <= 0) {
+ l = 0.001; // Avoid crashor.
+ }
- {
- float time_min = 0;
- float time_max = animation->get_length();
- for (int i = 0; i < animation->get_track_count(); i++) {
- if (animation->track_get_key_count(i) > 0) {
- float beg = animation->track_get_key_time(i, 0);
+ Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons"));
+ hsize_rect = Rect2(get_name_limit() - hsize_icon->get_width() - 2 * EDSCALE, (get_size().height - hsize_icon->get_height()) / 2, hsize_icon->get_width(), hsize_icon->get_height());
+ draw_texture(hsize_icon, hsize_rect.position);
- if (beg < time_min) {
- time_min = beg;
- }
+ {
+ float time_min = 0;
+ float time_max = animation->get_length();
+ for (int i = 0; i < animation->get_track_count(); i++) {
+ if (animation->track_get_key_count(i) > 0) {
+ float beg = animation->track_get_key_time(i, 0);
+
+ if (beg < time_min) {
+ time_min = beg;
+ }
- float end = animation->track_get_key_time(i, animation->track_get_key_count(i) - 1);
+ float end = animation->track_get_key_time(i, animation->track_get_key_count(i) - 1);
- if (end > time_max) {
- time_max = end;
+ if (end > time_max) {
+ time_max = end;
+ }
}
}
- }
- float extra = (zoomw / scale) * 0.5;
+ float extra = (zoomw / scale) * 0.5;
- time_max += extra;
- set_min(time_min);
- set_max(time_max);
+ time_max += extra;
+ set_min(time_min);
+ set_max(time_max);
- if (zoomw / scale < (time_max - time_min)) {
- hscroll->show();
+ if (zoomw / scale < (time_max - time_min)) {
+ hscroll->show();
- } else {
- hscroll->hide();
+ } else {
+ hscroll->hide();
+ }
}
- }
- set_page(zoomw / scale);
+ set_page(zoomw / scale);
- int end_px = (l - get_value()) * scale;
- int begin_px = -get_value() * scale;
- Color notimecol = get_theme_color(SNAME("dark_color_2"), SNAME("Editor"));
- Color timecolor = color;
- timecolor.a = 0.2;
- Color linecolor = color;
- linecolor.a = 0.2;
+ int end_px = (l - get_value()) * scale;
+ int begin_px = -get_value() * scale;
+ Color notimecol = get_theme_color(SNAME("dark_color_2"), SNAME("Editor"));
+ Color timecolor = color;
+ timecolor.a = 0.2;
+ Color linecolor = color;
+ linecolor.a = 0.2;
- {
- draw_rect(Rect2(Point2(get_name_limit(), 0), Point2(zoomw - 1, h)), notimecol);
+ {
+ draw_rect(Rect2(Point2(get_name_limit(), 0), Point2(zoomw - 1, h)), notimecol);
- if (begin_px < zoomw && end_px > 0) {
- if (begin_px < 0) {
- begin_px = 0;
- }
- if (end_px > zoomw) {
- end_px = zoomw;
- }
+ if (begin_px < zoomw && end_px > 0) {
+ if (begin_px < 0) {
+ begin_px = 0;
+ }
+ if (end_px > zoomw) {
+ end_px = zoomw;
+ }
- draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px - 1, h)), timecolor);
+ draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px - 1, h)), timecolor);
+ }
}
- }
- Color color_time_sec = color;
- Color color_time_dec = color;
- color_time_dec.a *= 0.5;
+ Color color_time_sec = color;
+ Color color_time_dec = color;
+ color_time_dec.a *= 0.5;
#define SC_ADJ 100
- int min = 30;
- int dec = 1;
- int step = 1;
- int decimals = 2;
- bool step_found = false;
-
- const int period_width = font->get_char_size('.', 0, font_size).width;
- int max_digit_width = font->get_char_size('0', 0, font_size).width;
- for (int i = 1; i <= 9; i++) {
- const int digit_width = font->get_char_size('0' + i, 0, font_size).width;
- max_digit_width = MAX(digit_width, max_digit_width);
- }
- const int max_sc = int(Math::ceil(zoomw / scale));
- const int max_sc_width = String::num(max_sc).length() * max_digit_width;
-
- while (!step_found) {
- min = max_sc_width;
- if (decimals > 0) {
- min += period_width + max_digit_width * decimals;
+ int dec = 1;
+ int step = 1;
+ int decimals = 2;
+ bool step_found = false;
+
+ const float period_width = font->get_char_size('.', font_size).width;
+ float max_digit_width = font->get_char_size('0', font_size).width;
+ for (int i = 1; i <= 9; i++) {
+ const float digit_width = font->get_char_size('0' + i, font_size).width;
+ max_digit_width = MAX(digit_width, max_digit_width);
}
+ const int max_sc = int(Math::ceil(zoomw / scale));
+ const int max_sc_width = String::num(max_sc).length() * max_digit_width;
- static const int _multp[3] = { 1, 2, 5 };
- for (int i = 0; i < 3; i++) {
- step = (_multp[i] * dec);
- if (step * scale / SC_ADJ > min) {
- step_found = true;
+ while (!step_found) {
+ int min = max_sc_width;
+ if (decimals > 0) {
+ min += period_width + max_digit_width * decimals;
+ }
+
+ static const int _multp[3] = { 1, 2, 5 };
+ for (int i = 0; i < 3; i++) {
+ step = (_multp[i] * dec);
+ if (step * scale / SC_ADJ > min) {
+ step_found = true;
+ break;
+ }
+ }
+ if (step_found) {
break;
}
+ dec *= 10;
+ decimals--;
+ if (decimals < 0) {
+ decimals = 0;
+ }
}
- if (step_found) {
- break;
- }
- dec *= 10;
- decimals--;
- if (decimals < 0) {
- decimals = 0;
- }
- }
- if (use_fps) {
- float step_size = animation->get_step();
- if (step_size > 0) {
- int prev_frame_ofs = -10000000;
+ if (use_fps) {
+ float step_size = animation->get_step();
+ if (step_size > 0) {
+ int prev_frame_ofs = -10000000;
- for (int i = 0; i < zoomw; i++) {
- float pos = get_value() + double(i) / scale;
- float prev = get_value() + (double(i) - 1.0) / scale;
+ for (int i = 0; i < zoomw; i++) {
+ float pos = get_value() + double(i) / scale;
+ float prev = get_value() + (double(i) - 1.0) / scale;
- int frame = pos / step_size;
- int prev_frame = prev / step_size;
+ int frame = pos / step_size;
+ int prev_frame = prev / step_size;
- bool sub = Math::floor(prev) == Math::floor(pos);
+ bool sub = Math::floor(prev) == Math::floor(pos);
- if (frame != prev_frame && i >= prev_frame_ofs) {
- draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE));
+ if (frame != prev_frame && i >= prev_frame_ofs) {
+ draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE));
- draw_string(font, Point2(get_name_limit() + i + 3 * EDSCALE, (h - font->get_height(font_size)) / 2 + font->get_ascent(font_size)).floor(), itos(frame), HORIZONTAL_ALIGNMENT_LEFT, zoomw - i, font_size, sub ? color_time_dec : color_time_sec);
- prev_frame_ofs = i + font->get_string_size(itos(frame), font_size).x + 5 * EDSCALE;
+ draw_string(font, Point2(get_name_limit() + i + 3 * EDSCALE, (h - font->get_height(font_size)) / 2 + font->get_ascent(font_size)).floor(), itos(frame), HORIZONTAL_ALIGNMENT_LEFT, zoomw - i, font_size, sub ? color_time_dec : color_time_sec);
+ prev_frame_ofs = i + font->get_string_size(itos(frame), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size).x + 5 * EDSCALE;
+ }
}
}
- }
- } else {
- for (int i = 0; i < zoomw; i++) {
- float pos = get_value() + double(i) / scale;
- float prev = get_value() + (double(i) - 1.0) / scale;
-
- int sc = int(Math::floor(pos * SC_ADJ));
- int prev_sc = int(Math::floor(prev * SC_ADJ));
- bool sub = (sc % SC_ADJ);
-
- if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
- int scd = sc < 0 ? prev_sc : sc;
- draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE));
- draw_string(font, Point2(get_name_limit() + i + 3, (h - font->get_height(font_size)) / 2 + font->get_ascent(font_size)).floor(), String::num((scd - (scd % step)) / double(SC_ADJ), decimals), HORIZONTAL_ALIGNMENT_LEFT, zoomw - i, font_size, sub ? color_time_dec : color_time_sec);
+ } else {
+ for (int i = 0; i < zoomw; i++) {
+ float pos = get_value() + double(i) / scale;
+ float prev = get_value() + (double(i) - 1.0) / scale;
+
+ int sc = int(Math::floor(pos * SC_ADJ));
+ int prev_sc = int(Math::floor(prev * SC_ADJ));
+ bool sub = (sc % SC_ADJ);
+
+ if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
+ int scd = sc < 0 ? prev_sc : sc;
+ draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE));
+ draw_string(font, Point2(get_name_limit() + i + 3, (h - font->get_height(font_size)) / 2 + font->get_ascent(font_size)).floor(), String::num((scd - (scd % step)) / double(SC_ADJ), decimals), HORIZONTAL_ALIGNMENT_LEFT, zoomw - i, font_size, sub ? color_time_dec : color_time_sec);
+ }
}
}
- }
- draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
+ draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
+ } break;
}
}
-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;
+ 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();
@@ -1722,15 +1753,15 @@ void AnimationTimelineEdit::update_values() {
}
switch (animation->get_loop_mode()) {
- case Animation::LoopMode::LOOP_NONE: {
+ case Animation::LOOP_NONE: {
loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons")));
loop->set_pressed(false);
} break;
- case Animation::LoopMode::LOOP_LINEAR: {
+ case Animation::LOOP_LINEAR: {
loop->set_icon(get_theme_icon(SNAME("Loop"), SNAME("EditorIcons")));
loop->set_pressed(true);
} break;
- case Animation::LoopMode::LOOP_PINGPONG: {
+ case Animation::LOOP_PINGPONG: {
loop->set_icon(get_theme_icon(SNAME("PingPongLoop"), SNAME("EditorIcons")));
loop->set_pressed(true);
} break;
@@ -1811,13 +1842,6 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- if (hsize_rect.has_point(mm->get_position())) {
- // Change the cursor to indicate that the track name column's width can be adjusted
- set_default_cursor_shape(Control::CURSOR_HSIZE);
- } else {
- set_default_cursor_shape(Control::CURSOR_ARROW);
- }
-
if (dragging_hsize) {
int ofs = mm->get_position().x - dragging_hsize_from;
name_limit = dragging_hsize_at + ofs;
@@ -1833,6 +1857,15 @@ void AnimationTimelineEdit::gui_input(const Ref<InputEvent> &p_event) {
}
}
+Control::CursorShape AnimationTimelineEdit::get_cursor_shape(const Point2 &p_pos) const {
+ if (dragging_hsize || hsize_rect.has_point(p_pos)) {
+ // Indicate that the track name column's width can be adjusted
+ return Control::CURSOR_HSIZE;
+ } else {
+ return get_default_cursor_shape();
+ }
+}
+
void AnimationTimelineEdit::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
// Timeline has no vertical scroll, so we change it to horizontal.
p_scroll_vec.x += p_scroll_vec.y;
@@ -1844,11 +1877,14 @@ void AnimationTimelineEdit::_pan_callback(Vector2 p_scroll_vec) {
}
void AnimationTimelineEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- if (p_scroll_vec.y < 0) {
- get_zoom()->set_value(get_zoom()->get_value() * 1.05);
+ double new_zoom_value;
+ double current_zoom_value = get_zoom()->get_value();
+ if (current_zoom_value <= 0.1) {
+ new_zoom_value = MAX(0.01, current_zoom_value - 0.01 * SIGN(p_scroll_vec.y));
} else {
- get_zoom()->set_value(get_zoom()->get_value() / 1.05);
+ new_zoom_value = p_scroll_vec.y > 0 ? MAX(0.01, current_zoom_value / 1.05) : current_zoom_value * 1.05;
}
+ get_zoom()->set_value(new_zoom_value);
}
void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
@@ -1878,17 +1914,12 @@ void AnimationTimelineEdit::_bind_methods() {
}
AnimationTimelineEdit::AnimationTimelineEdit() {
- use_fps = false;
- editing = false;
name_limit = 150 * EDSCALE;
- zoom = nullptr;
- track_edit = nullptr;
- play_position_pos = 0;
play_position = memnew(Control);
play_position->set_mouse_filter(MOUSE_FILTER_PASS);
add_child(play_position);
- play_position->set_anchors_and_offsets_preset(PRESET_WIDE);
+ play_position->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
play_position->connect("draw", callable_mp(this, &AnimationTimelineEdit::_play_position_draw));
add_track = memnew(MenuButton);
@@ -1927,9 +1958,6 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
add_track->get_popup()->connect("index_pressed", callable_mp(this, &AnimationTimelineEdit::_track_added));
len_hb->hide();
- dragging_timeline = false;
- dragging_hsize = false;
-
panner.instantiate();
panner->set_callbacks(callable_mp(this, &AnimationTimelineEdit::_scroll_callback), callable_mp(this, &AnimationTimelineEdit::_pan_callback), callable_mp(this, &AnimationTimelineEdit::_zoom_callback));
@@ -1939,302 +1967,333 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
////////////////////////////////////
void AnimationTrackEdit::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
- if (animation.is_null()) {
- return;
- }
- ERR_FAIL_INDEX(track, animation->get_track_count());
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ if (animation.is_null()) {
+ return;
+ }
+ ERR_FAIL_INDEX(track, animation->get_track_count());
- int limit = timeline->get_name_limit();
+ type_icon = _get_key_type_icon();
+ selected_icon = get_theme_icon(SNAME("KeySelected"), SNAME("EditorIcons"));
+ } break;
- if (has_focus()) {
- Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- accent.a *= 0.7;
- // Offside so the horizontal sides aren't cutoff.
- draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), accent, false);
- }
+ case NOTIFICATION_DRAW: {
+ if (animation.is_null()) {
+ return;
+ }
+ ERR_FAIL_INDEX(track, animation->get_track_count());
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
- Ref<Texture2D> type_icons[9] = {
- get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyTrackPosition"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyTrackRotation"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyTrackScale"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyTrackBlendShape"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyAnimation"), SNAME("EditorIcons"))
- };
- int hsep = get_theme_constant(SNAME("hseparation"), SNAME("ItemList"));
- Color linecolor = color;
- linecolor.a = 0.2;
+ int limit = timeline->get_name_limit();
- // NAMES AND ICONS //
+ if (track % 2 == 1) {
+ // Draw a background over odd lines to make long lists of tracks easier to read.
+ draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), Color(0.5, 0.5, 0.5, 0.05));
+ }
- {
- Ref<Texture2D> check = animation->track_is_enabled(track) ? get_theme_icon(SNAME("checked"), SNAME("CheckBox")) : get_theme_icon(SNAME("unchecked"), SNAME("CheckBox"));
+ if (hovered) {
+ // Draw hover feedback.
+ draw_rect(Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)), Color(0.5, 0.5, 0.5, 0.1));
+ }
- int ofs = in_group ? check->get_width() : 0; // Not the best reference for margin but..
+ if (has_focus()) {
+ Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ accent.a *= 0.7;
+ // Offside so the horizontal sides aren't cutoff.
+ draw_style_box(get_theme_stylebox(SNAME("Focus"), SNAME("EditorStyles")), Rect2(Point2(1 * EDSCALE, 0), get_size() - Size2(1 * EDSCALE, 0)));
+ }
- check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size());
- draw_texture(check, check_rect.position);
- ofs += check->get_width() + hsep;
+ Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
+ int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
+ Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
+ int hsep = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
+ Color linecolor = color;
+ linecolor.a = 0.2;
- Ref<Texture2D> type_icon = type_icons[animation->track_get_type(track)];
- draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2));
- ofs += type_icon->get_width() + hsep;
+ Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
- NodePath path = animation->track_get_path(track);
- Node *node = nullptr;
- if (root && root->has_node(path)) {
- node = root->get_node(path);
- }
+ // NAMES AND ICONS //
- String text;
- Color text_color = color;
- if (node && EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
- text_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- }
+ {
+ Ref<Texture2D> check = animation->track_is_enabled(track) ? get_theme_icon(SNAME("checked"), SNAME("CheckBox")) : get_theme_icon(SNAME("unchecked"), SNAME("CheckBox"));
- if (in_group) {
- if (animation->track_get_type(track) == Animation::TYPE_METHOD) {
- text = TTR("Functions:");
- } else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) {
- text = TTR("Audio Clips:");
- } else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) {
- text = TTR("Anim Clips:");
- } else {
- text += path.get_concatenated_subnames();
+ int ofs = in_group ? check->get_width() : 0; // Not the best reference for margin but..
+
+ check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size());
+ draw_texture(check, check_rect.position);
+ ofs += check->get_width() + hsep;
+
+ Ref<Texture2D> type_icon = _get_key_type_icon();
+ draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2));
+ ofs += type_icon->get_width() + hsep;
+
+ NodePath path = animation->track_get_path(track);
+ Node *node = nullptr;
+ if (root && root->has_node(path)) {
+ node = root->get_node(path);
}
- text_color.a *= 0.7;
- } else if (node) {
- Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(node, "Node");
- draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
- icon_cache = icon;
+ String text;
+ Color text_color = color;
+ if (node && EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
+ text_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ }
- text = String() + node->get_name() + ":" + path.get_concatenated_subnames();
- ofs += hsep;
- ofs += icon->get_width();
+ if (in_group) {
+ if (animation->track_get_type(track) == Animation::TYPE_METHOD) {
+ text = TTR("Functions:");
+ } else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) {
+ text = TTR("Audio Clips:");
+ } else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) {
+ text = TTR("Anim Clips:");
+ } else {
+ text += path.get_concatenated_subnames();
+ }
+ text_color.a *= 0.7;
+ } else if (node) {
+ Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(node, "Node");
- } else {
- icon_cache = type_icon;
+ draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
+ icon_cache = icon;
- text = path;
- }
+ text = String() + node->get_name() + ":" + path.get_concatenated_subnames();
+ ofs += hsep;
+ ofs += icon->get_width();
+
+ } else {
+ icon_cache = type_icon;
- path_cache = text;
+ text = path;
+ }
- path_rect = Rect2(ofs, 0, limit - ofs - hsep, get_size().height);
+ path_cache = text;
- Vector2 string_pos = Point2(ofs, (get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size));
- string_pos = string_pos.floor();
- draw_string(font, string_pos, text, HORIZONTAL_ALIGNMENT_LEFT, limit - ofs - hsep, font_size, text_color);
+ path_rect = Rect2(ofs, 0, limit - ofs - hsep, get_size().height);
- draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE));
- }
+ Vector2 string_pos = Point2(ofs, (get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size));
+ string_pos = string_pos.floor();
+ draw_string(font, string_pos, text, HORIZONTAL_ALIGNMENT_LEFT, limit - ofs - hsep, font_size, text_color);
- // KEYFRAMES //
+ draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE));
+ }
- draw_bg(limit, get_size().width - timeline->get_buttons_width());
+ // KEYFRAMES //
- {
- float scale = timeline->get_zoom_scale();
- int limit_end = get_size().width - timeline->get_buttons_width();
+ draw_bg(limit, get_size().width - timeline->get_buttons_width());
- for (int i = 0; i < animation->track_get_key_count(track); i++) {
- float offset = animation->track_get_key_time(track, i) - timeline->get_value();
- if (editor->is_key_selected(track, i) && editor->is_moving_selection()) {
- offset = editor->snap_time(offset + editor->get_moving_selection_offset(), true);
- }
- offset = offset * scale + limit;
- if (i < animation->track_get_key_count(track) - 1) {
- float offset_n = animation->track_get_key_time(track, i + 1) - timeline->get_value();
- if (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) {
- offset_n = editor->snap_time(offset_n + editor->get_moving_selection_offset());
+ {
+ float scale = timeline->get_zoom_scale();
+ int limit_end = get_size().width - timeline->get_buttons_width();
+
+ for (int i = 0; i < animation->track_get_key_count(track); i++) {
+ float offset = animation->track_get_key_time(track, i) - timeline->get_value();
+ if (editor->is_key_selected(track, i) && editor->is_moving_selection()) {
+ offset = editor->snap_time(offset + editor->get_moving_selection_offset(), true);
+ }
+ offset = offset * scale + limit;
+ if (i < animation->track_get_key_count(track) - 1) {
+ float offset_n = animation->track_get_key_time(track, i + 1) - timeline->get_value();
+ if (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) {
+ offset_n = editor->snap_time(offset_n + editor->get_moving_selection_offset());
+ }
+ offset_n = offset_n * scale + limit;
+
+ draw_key_link(i, scale, int(offset), int(offset_n), limit, limit_end);
}
- offset_n = offset_n * scale + limit;
- draw_key_link(i, scale, int(offset), int(offset_n), limit, limit_end);
+ draw_key(i, scale, int(offset), editor->is_key_selected(track, i), limit, limit_end);
}
-
- draw_key(i, scale, int(offset), editor->is_key_selected(track, i), limit, limit_end);
}
- }
- draw_fg(limit, get_size().width - timeline->get_buttons_width());
+ draw_fg(limit, get_size().width - timeline->get_buttons_width());
- // BUTTONS //
+ // BUTTONS //
- {
- Ref<Texture2D> wrap_icon[2] = {
- get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")),
- };
-
- Ref<Texture2D> interp_icon[3] = {
- get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons"))
- };
- Ref<Texture2D> cont_icon[4] = {
- get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons"))
- };
-
- int ofs = get_size().width - timeline->get_buttons_width();
-
- Ref<Texture2D> down_icon = get_theme_icon(SNAME("select_arrow"), SNAME("Tree"));
-
- draw_line(Point2(ofs, 0), Point2(ofs, get_size().height), linecolor, Math::round(EDSCALE));
-
- ofs += hsep;
{
- // Callmode.
+ Ref<Texture2D> wrap_icon[2] = {
+ get_theme_icon(SNAME("InterpWrapClamp"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpWrapLoop"), SNAME("EditorIcons")),
+ };
- Animation::UpdateMode update_mode;
+ Ref<Texture2D> interp_icon[3] = {
+ get_theme_icon(SNAME("InterpRaw"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpLinear"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("InterpCubic"), SNAME("EditorIcons"))
+ };
+ Ref<Texture2D> cont_icon[4] = {
+ get_theme_icon(SNAME("TrackContinuous"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("TrackDiscrete"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("TrackTrigger"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("TrackCapture"), SNAME("EditorIcons"))
+ };
- if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
- update_mode = animation->value_track_get_update_mode(track);
- } else {
- update_mode = Animation::UPDATE_CONTINUOUS;
- }
+ int ofs = get_size().width - timeline->get_buttons_width();
- Ref<Texture2D> update_icon = cont_icon[update_mode];
+ Ref<Texture2D> down_icon = get_theme_icon(SNAME("select_arrow"), SNAME("Tree"));
- update_mode_rect.position.x = ofs;
- update_mode_rect.position.y = int(get_size().height - update_icon->get_height()) / 2;
- update_mode_rect.size = update_icon->get_size();
+ draw_line(Point2(ofs, 0), Point2(ofs, get_size().height), linecolor, Math::round(EDSCALE));
- if (!animation->track_is_compressed(track) && animation->track_get_type(track) == Animation::TYPE_VALUE) {
- draw_texture(update_icon, update_mode_rect.position);
- }
- // Make it easier to click.
- update_mode_rect.position.y = 0;
- update_mode_rect.size.y = get_size().height;
+ ofs += hsep;
+ {
+ // Callmode.
+
+ Animation::UpdateMode update_mode;
- ofs += update_icon->get_width() + hsep / 2;
- update_mode_rect.size.x += hsep / 2;
+ if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
+ update_mode = animation->value_track_get_update_mode(track);
+ } else {
+ update_mode = Animation::UPDATE_CONTINUOUS;
+ }
- 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<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
- update_mode_rect.size.x += down_icon->get_width();
+ Ref<Texture2D> update_icon = cont_icon[update_mode];
- update_mode_rect = Rect2();
- } else {
- update_mode_rect = Rect2();
+ update_mode_rect.position.x = ofs;
+ update_mode_rect.position.y = int(get_size().height - update_icon->get_height()) / 2;
+ update_mode_rect.size = update_icon->get_size();
+
+ if (!animation->track_is_compressed(track) && animation->track_get_type(track) == Animation::TYPE_VALUE) {
+ draw_texture(update_icon, update_mode_rect.position);
+ }
+ // Make it easier to click.
+ update_mode_rect.position.y = 0;
+ update_mode_rect.size.y = get_size().height;
+
+ ofs += update_icon->get_width() + hsep / 2;
+ update_mode_rect.size.x += hsep / 2;
+
+ 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<Texture2D> bezier_icon = get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons"));
+ update_mode_rect.size.x += down_icon->get_width();
+
+ update_mode_rect = Rect2();
+ } else {
+ update_mode_rect = Rect2();
+ }
+ } else {
+ update_mode_rect = Rect2();
+ }
+
+ ofs += down_icon->get_width();
+ draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
+ ofs += hsep;
}
- ofs += down_icon->get_width();
- draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
- ofs += hsep;
- }
+ {
+ // Interp.
- {
- // Interp.
+ Animation::InterpolationType interp_mode = animation->track_get_interpolation_type(track);
- Animation::InterpolationType interp_mode = animation->track_get_interpolation_type(track);
+ Ref<Texture2D> icon = interp_icon[interp_mode];
- Ref<Texture2D> icon = interp_icon[interp_mode];
+ interp_mode_rect.position.x = ofs;
+ interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
+ interp_mode_rect.size = icon->get_size();
- interp_mode_rect.position.x = ofs;
- interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
- interp_mode_rect.size = icon->get_size();
+ 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)) {
+ draw_texture(icon, interp_mode_rect.position);
+ }
+ // Make it easier to click.
+ interp_mode_rect.position.y = 0;
+ interp_mode_rect.size.y = get_size().height;
- 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)) {
- draw_texture(icon, interp_mode_rect.position);
- }
- // Make it easier to click.
- interp_mode_rect.position.y = 0;
- interp_mode_rect.size.y = get_size().height;
+ ofs += icon->get_width() + hsep / 2;
+ interp_mode_rect.size.x += hsep / 2;
- ofs += icon->get_width() + hsep / 2;
- interp_mode_rect.size.x += hsep / 2;
+ 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 {
+ interp_mode_rect = Rect2();
+ }
- 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)) {
- 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 {
- interp_mode_rect = Rect2();
+ ofs += down_icon->get_width();
+ draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
+ ofs += hsep;
}
- ofs += down_icon->get_width();
- draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
- ofs += hsep;
- }
+ {
+ // Loop.
- {
- // Loop.
+ bool loop_wrap = animation->track_get_interpolation_loop_wrap(track);
- bool loop_wrap = animation->track_get_interpolation_loop_wrap(track);
+ Ref<Texture2D> icon = wrap_icon[loop_wrap ? 1 : 0];
- Ref<Texture2D> icon = wrap_icon[loop_wrap ? 1 : 0];
+ loop_wrap_rect.position.x = ofs;
+ loop_wrap_rect.position.y = int(get_size().height - icon->get_height()) / 2;
+ loop_wrap_rect.size = icon->get_size();
- loop_wrap_rect.position.x = ofs;
- loop_wrap_rect.position.y = int(get_size().height - icon->get_height()) / 2;
- loop_wrap_rect.size = icon->get_size();
+ 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)) {
+ draw_texture(icon, loop_wrap_rect.position);
+ }
- 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)) {
- draw_texture(icon, loop_wrap_rect.position);
- }
+ loop_wrap_rect.position.y = 0;
+ loop_wrap_rect.size.y = get_size().height;
- loop_wrap_rect.position.y = 0;
- loop_wrap_rect.size.y = get_size().height;
+ ofs += icon->get_width() + hsep / 2;
+ loop_wrap_rect.size.x += hsep / 2;
- ofs += icon->get_width() + hsep / 2;
- loop_wrap_rect.size.x += hsep / 2;
+ 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 {
+ loop_wrap_rect = Rect2();
+ }
- 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)) {
- 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 {
- loop_wrap_rect = Rect2();
+ ofs += down_icon->get_width();
+ draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
+ ofs += hsep;
}
- ofs += down_icon->get_width();
- draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
- ofs += hsep;
- }
-
- {
- // Erase.
+ {
+ // Erase.
- Ref<Texture2D> icon = get_theme_icon(animation->track_is_compressed(track) ? SNAME("Lock") : SNAME("Remove"), SNAME("EditorIcons"));
+ Ref<Texture2D> icon = get_theme_icon(animation->track_is_compressed(track) ? SNAME("Lock") : SNAME("Remove"), SNAME("EditorIcons"));
- remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width());
- remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
- remove_rect.size = icon->get_size();
+ remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width());
+ 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);
+ }
+ }
}
- }
- if (in_group) {
- draw_line(Vector2(timeline->get_name_limit(), get_size().height), get_size(), linecolor, Math::round(EDSCALE));
- } else {
- draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
- }
-
- if (dropping_at != 0) {
- Color drop_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- if (dropping_at < 0) {
- draw_line(Vector2(0, 0), Vector2(get_size().width, 0), drop_color, Math::round(EDSCALE));
+ if (in_group) {
+ draw_line(Vector2(timeline->get_name_limit(), get_size().height), get_size(), linecolor, Math::round(EDSCALE));
} else {
- draw_line(Vector2(0, get_size().height), get_size(), drop_color, Math::round(EDSCALE));
+ draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
}
- }
- }
- if (p_what == NOTIFICATION_MOUSE_EXIT || p_what == NOTIFICATION_DRAG_END) {
- cancel_drop();
+ if (dropping_at != 0) {
+ Color drop_color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ if (dropping_at < 0) {
+ draw_line(Vector2(0, 0), Vector2(get_size().width, 0), drop_color, Math::round(EDSCALE));
+ } else {
+ draw_line(Vector2(0, get_size().height), get_size(), drop_color, Math::round(EDSCALE));
+ }
+ }
+ } break;
+
+ case NOTIFICATION_MOUSE_ENTER:
+ hovered = true;
+ update();
+ break;
+ case NOTIFICATION_MOUSE_EXIT:
+ hovered = false;
+ // When the mouse cursor exits the track, we're no longer hovering any keyframe.
+ hovering_key_idx = -1;
+ update();
+ [[fallthrough]];
+ case NOTIFICATION_DRAG_END: {
+ cancel_drop();
+ } break;
}
}
@@ -2343,7 +2402,13 @@ void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool
}
}
- draw_texture(icon_to_draw, ofs);
+ // Use a different color for the currently hovered key.
+ // The color multiplier is chosen to work with both dark and light editor themes,
+ // and on both unselected and selected key icons.
+ draw_texture(
+ icon_to_draw,
+ ofs,
+ p_index == hovering_key_idx ? get_theme_color(SNAME("folder_icon_modulate"), SNAME("FileDialog")) : Color(1, 1, 1));
}
// Helper.
@@ -2412,27 +2477,17 @@ Ref<Animation> AnimationTrackEdit::get_animation() const {
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;
+ read_only = p_read_only;
+
track = p_track;
update();
- Ref<Texture2D> type_icons[9] = {
- get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyXPosition"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyXRotation"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyXScale"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyBlendShape"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")),
- get_theme_icon(SNAME("KeyAnimation"), SNAME("EditorIcons"))
- };
-
ERR_FAIL_INDEX(track, animation->get_track_count());
node_path = animation->track_get_path(p_track);
- type_icon = type_icons[animation->track_get_type(track)];
+ type_icon = _get_key_type_icon();
selected_icon = get_theme_icon(SNAME("KeySelected"), SNAME("EditorIcons"));
}
@@ -2444,7 +2499,7 @@ Size2 AnimationTrackEdit::get_minimum_size() const {
Ref<Texture2D> texture = get_theme_icon(SNAME("Object"), SNAME("EditorIcons"));
Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- int separation = get_theme_constant(SNAME("vseparation"), SNAME("ItemList"));
+ int separation = get_theme_constant(SNAME("v_separation"), SNAME("ItemList"));
int max_h = MAX(texture->get_height(), font->get_height(font_size));
max_h = MAX(max_h, get_key_height());
@@ -2514,7 +2569,7 @@ bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant
return false;
}
- RES res;
+ Ref<Resource> res;
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path);
@@ -2533,6 +2588,21 @@ bool AnimationTrackEdit::_is_value_key_valid(const Variant &p_key_value, Variant
return (!prop_exists || Variant::can_convert(p_key_value.get_type(), r_valid_type));
}
+Ref<Texture2D> AnimationTrackEdit::_get_key_type_icon() const {
+ const Ref<Texture2D> type_icons[9] = {
+ get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyTrackPosition"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyTrackRotation"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyTrackScale"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyTrackBlendShape"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyCall"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyBezier"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyAudio"), SNAME("EditorIcons")),
+ get_theme_icon(SNAME("KeyAnimation"), SNAME("EditorIcons"))
+ };
+ return type_icons[animation->track_get_type(track)];
+}
+
String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
if (check_rect.has_point(p_pos)) {
return TTR("Toggle this track on/off.");
@@ -2590,34 +2660,33 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
if (key_idx != -1) {
- String text = TTR("Time (s): ") + rtos(animation->track_get_key_time(track, key_idx)) + "\n";
+ String text = TTR("Time (s):") + " " + rtos(animation->track_get_key_time(track, key_idx)) + "\n";
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
- text += "Position: " + String(t) + "\n";
+ text += TTR("Position:") + " " + String(t) + "\n";
} break;
case Animation::TYPE_ROTATION_3D: {
Quaternion t = animation->track_get_key_value(track, key_idx);
- text += "Rotation: " + String(t) + "\n";
+ text += TTR("Rotation:") + " " + String(t) + "\n";
} break;
case Animation::TYPE_SCALE_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx);
- text += "Scale: " + String(t) + "\n";
+ text += TTR("Scale:") + " " + String(t) + "\n";
} break;
case Animation::TYPE_BLEND_SHAPE: {
float t = animation->track_get_key_value(track, key_idx);
- text += "Blend Shape: " + itos(t) + "\n";
+ text += TTR("Blend Shape:") + " " + itos(t) + "\n";
} break;
case Animation::TYPE_VALUE: {
const Variant &v = animation->track_get_key_value(track, key_idx);
- text += "Type: " + Variant::get_type_name(v.get_type()) + "\n";
+ text += TTR("Type:") + " " + Variant::get_type_name(v.get_type()) + "\n";
Variant::Type valid_type = Variant::NIL;
+ text += TTR("Value:") + " " + String(v);
if (!_is_value_key_valid(v, valid_type)) {
- text += "Value: " + String(v) + " (Invalid, expected type: " + Variant::get_type_name(valid_type) + ")\n";
- } else {
- text += "Value: " + String(v) + "\n";
+ text += " " + vformat(TTR("(Invalid, expected type: %s)"), Variant::get_type_name(valid_type));
}
- text += "Easing: " + rtos(animation->track_get_key_transition(track, key_idx));
+ text += "\n" + TTR("Easing:") + " " + rtos(animation->track_get_key_transition(track, key_idx));
} break;
case Animation::TYPE_METHOD: {
@@ -2641,26 +2710,24 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
} break;
case Animation::TYPE_BEZIER: {
float h = animation->bezier_track_get_key_value(track, key_idx);
- text += "Value: " + rtos(h) + "\n";
+ text += TTR("Value:") + " " + rtos(h) + "\n";
Vector2 ih = animation->bezier_track_get_key_in_handle(track, key_idx);
- text += "In-Handle: " + ih + "\n";
+ text += TTR("In-Handle:") + " " + ih + "\n";
Vector2 oh = animation->bezier_track_get_key_out_handle(track, key_idx);
- text += "Out-Handle: " + oh + "\n";
+ text += TTR("Out-Handle:") + " " + oh + "\n";
int hm = animation->bezier_track_get_key_handle_mode(track, key_idx);
- text += "Handle mode: ";
switch (hm) {
case Animation::HANDLE_MODE_FREE: {
- text += "Free";
+ text += TTR("Handle mode: Free\n");
} break;
case Animation::HANDLE_MODE_BALANCED: {
- text += "Balanced";
+ text += TTR("Handle mode: Balanced\n");
} break;
}
- text += "\n";
} break;
case Animation::TYPE_AUDIO: {
String stream_name = "null";
- RES stream = animation->audio_track_get_key_stream(track, key_idx);
+ Ref<Resource> stream = animation->audio_track_get_key_stream(track, key_idx);
if (stream.is_valid()) {
if (stream->get_path().is_resource_file()) {
stream_name = stream->get_path().get_file();
@@ -2671,15 +2738,15 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
}
}
- text += "Stream: " + stream_name + "\n";
+ text += TTR("Stream:") + " " + stream_name + "\n";
float so = animation->audio_track_get_key_start_offset(track, key_idx);
- text += "Start (s): " + rtos(so) + "\n";
+ text += TTR("Start (s):") + " " + rtos(so) + "\n";
float eo = animation->audio_track_get_key_end_offset(track, key_idx);
- text += "End (s): " + rtos(eo) + "\n";
+ text += TTR("End (s):") + " " + rtos(eo) + "\n";
} break;
case Animation::TYPE_ANIMATION: {
String name = animation->animation_track_get_key_animation(track, key_idx);
- text += "Animation Clip: " + name + "\n";
+ text += TTR("Animation Clip:") + " " + name + "\n";
} break;
}
return text;
@@ -2694,17 +2761,23 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &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();
}
}
@@ -2713,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) {
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();
- }
+ 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();
+ }
- // 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();
- }
+ // 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 (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);
+ menu->set_position(popup_pos);
+ menu->popup();
+ 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->set_as_minsize();
-
- 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));
+ 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);
+ menu->set_position(popup_pos);
+ menu->popup();
+ 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->set_as_minsize();
-
- 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));
+ 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();
}
- 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->set_as_minsize();
-
- 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;
+ if (remove_rect.has_point(pos)) {
+ emit_signal(SNAME("remove_request"), track);
+ accept_event();
+ return;
+ }
}
// Check keyframes.
@@ -2845,6 +2920,11 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &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();
}
}
@@ -2856,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()) {
// 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));
- }
+ if (!read_only) {
+ 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);
+ 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);
- }
+ 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->set_as_minsize();
+ 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();
+ menu->set_position(get_screen_position() + get_local_mouse_position());
+ menu->popup();
- insert_at_pos = offset + timeline->get_value();
- accept_event();
+ insert_at_pos = offset + timeline->get_value();
+ accept_event();
+ }
}
}
@@ -2893,7 +2975,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
add_child(path_popup);
path = memnew(LineEdit);
path_popup->add_child(path);
- path->set_anchors_and_offsets_preset(PRESET_WIDE);
+ path->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
path->connect("text_submitted", callable_mp(this, &AnimationTrackEdit::_path_submitted));
}
@@ -2927,6 +3009,57 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
}
Ref<InputEventMouseMotion> mm = p_event;
+ if (mm.is_valid()) {
+ const int previous_hovering_key_idx = hovering_key_idx;
+
+ // Hovering compressed keyframes for editing is not possible.
+ if (!animation->track_is_compressed(track)) {
+ const float scale = timeline->get_zoom_scale();
+ const int limit = timeline->get_name_limit();
+ const int limit_end = get_size().width - timeline->get_buttons_width();
+ // Left Border including space occupied by keyframes on t=0.
+ const int limit_start_hitbox = limit - type_icon->get_width();
+ const Point2 pos = mm->get_position();
+
+ if (pos.x >= limit_start_hitbox && pos.x <= limit_end) {
+ // Use the same logic as key selection to ensure that hovering accurately represents
+ // which key will be selected when clicking.
+ int key_idx = -1;
+ float key_distance = 1e20;
+
+ hovering_key_idx = -1;
+
+ // Hovering should happen in the opposite order of drawing for more accurate overlap hovering.
+ for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) {
+ Rect2 rect = get_key_rect(i, scale);
+ float offset = animation->track_get_key_time(track, i) - timeline->get_value();
+ offset = offset * scale + limit;
+ rect.position.x += offset;
+
+ if (rect.has_point(pos)) {
+ if (is_key_selectable_by_distance()) {
+ const float distance = ABS(offset - pos.x);
+ if (key_idx == -1 || distance < key_distance) {
+ key_idx = i;
+ key_distance = distance;
+ hovering_key_idx = i;
+ }
+ } else {
+ // First one does it.
+ hovering_key_idx = i;
+ break;
+ }
+ }
+ }
+
+ if (hovering_key_idx != previous_hovering_key_idx) {
+ // Required to draw keyframe hover feedback on the correct keyframe.
+ update();
+ }
+ }
+ }
+ }
+
if (mm.is_valid() && (mm->get_button_mask() & MouseButton::MASK_LEFT) != MouseButton::NONE && moving_selection_attempt) {
if (!moving_selection) {
moving_selection = true;
@@ -3115,13 +3248,13 @@ void AnimationTrackEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag"), PropertyInfo(Variant::BOOL, "timeline_only")));
ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track")));
ADD_SIGNAL(MethodInfo("dropped", PropertyInfo(Variant::INT, "from_track"), PropertyInfo(Variant::INT, "to_track")));
- ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "ofs")));
+ ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset")));
ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index")));
ADD_SIGNAL(MethodInfo("bezier_edit"));
ADD_SIGNAL(MethodInfo("move_selection_begin"));
- ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::FLOAT, "ofs")));
+ ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::FLOAT, "offset")));
ADD_SIGNAL(MethodInfo("move_selection_commit"));
ADD_SIGNAL(MethodInfo("move_selection_cancel"));
@@ -3132,26 +3265,10 @@ void AnimationTrackEdit::_bind_methods() {
}
AnimationTrackEdit::AnimationTrackEdit() {
- undo_redo = nullptr;
- timeline = nullptr;
- root = nullptr;
- path = nullptr;
- path_popup = nullptr;
- menu = nullptr;
- clicking_on_name = false;
- dropping_at = 0;
-
- in_group = false;
-
- moving_selection_attempt = false;
- moving_selection = false;
- select_single_attempt = -1;
-
- play_position_pos = 0;
play_position = memnew(Control);
play_position->set_mouse_filter(MOUSE_FILTER_PASS);
add_child(play_position);
- play_position->set_anchors_and_offsets_preset(PRESET_WIDE);
+ play_position->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
play_position->connect("draw", callable_mp(this, &AnimationTrackEdit::_play_position_draw));
set_focus_mode(FOCUS_CLICK);
set_mouse_filter(MOUSE_FILTER_PASS); // Scroll has to work too for selection.
@@ -3180,7 +3297,7 @@ AnimationTrackEdit *AnimationTrackEditPlugin::create_value_track_edit(Object *p_
};
Callable::CallError ce;
- return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_value_track_edit", (const Variant **)&argptrs, 6, ce).operator Object *());
+ return Object::cast_to<AnimationTrackEdit>(get_script_instance()->callp("create_value_track_edit", (const Variant **)&argptrs, 6, ce).operator Object *());
}
return nullptr;
}
@@ -3202,40 +3319,42 @@ AnimationTrackEdit *AnimationTrackEditPlugin::create_animation_track_edit(Object
///////////////////////////////////////
void AnimationTrackEditGroup::_notification(int p_what) {
- if (p_what == NOTIFICATION_DRAW) {
- Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
- int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- int separation = get_theme_constant(SNAME("hseparation"), SNAME("ItemList"));
- Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
-
- if (root && root->has_node(node)) {
- Node *n = root->get_node(node);
- if (n && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
- color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ switch (p_what) {
+ case NOTIFICATION_DRAW: {
+ Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
+ int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
+ int separation = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
+ Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
+
+ if (root && root->has_node(node)) {
+ Node *n = root->get_node(node);
+ if (n && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
+ color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ }
}
- }
- Color bgcol = get_theme_color(SNAME("dark_color_2"), SNAME("Editor"));
- bgcol.a *= 0.6;
- draw_rect(Rect2(Point2(), get_size()), bgcol);
- Color linecolor = color;
- linecolor.a = 0.2;
+ Color bgcol = get_theme_color(SNAME("dark_color_2"), SNAME("Editor"));
+ bgcol.a *= 0.6;
+ draw_rect(Rect2(Point2(), get_size()), bgcol);
+ Color linecolor = color;
+ linecolor.a = 0.2;
- draw_line(Point2(), Point2(get_size().width, 0), linecolor, Math::round(EDSCALE));
- draw_line(Point2(timeline->get_name_limit(), 0), Point2(timeline->get_name_limit(), get_size().height), linecolor, Math::round(EDSCALE));
- draw_line(Point2(get_size().width - timeline->get_buttons_width(), 0), Point2(get_size().width - timeline->get_buttons_width(), get_size().height), linecolor, Math::round(EDSCALE));
+ draw_line(Point2(), Point2(get_size().width, 0), linecolor, Math::round(EDSCALE));
+ draw_line(Point2(timeline->get_name_limit(), 0), Point2(timeline->get_name_limit(), get_size().height), linecolor, Math::round(EDSCALE));
+ draw_line(Point2(get_size().width - timeline->get_buttons_width(), 0), Point2(get_size().width - timeline->get_buttons_width(), get_size().height), linecolor, Math::round(EDSCALE));
- int ofs = 0;
- draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
- ofs += separation + icon->get_width();
- draw_string(font, Point2(ofs, int(get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size)), node_name, HORIZONTAL_ALIGNMENT_LEFT, timeline->get_name_limit() - ofs, font_size, color);
+ int ofs = 0;
+ draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
+ ofs += separation + icon->get_width();
+ draw_string(font, Point2(ofs, int(get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size)), node_name, HORIZONTAL_ALIGNMENT_LEFT, timeline->get_name_limit() - ofs, font_size, color);
- int px = (-timeline->get_value() + timeline->get_play_position()) * timeline->get_zoom_scale() + timeline->get_name_limit();
+ int px = (-timeline->get_value() + timeline->get_play_position()) * timeline->get_zoom_scale() + timeline->get_name_limit();
- if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
- Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
- draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(2 * EDSCALE));
- }
+ if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
+ Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
+ draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(2 * EDSCALE));
+ }
+ } break;
}
}
@@ -3250,7 +3369,7 @@ void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture2D> &p_type, co
Size2 AnimationTrackEditGroup::get_minimum_size() const {
Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
- int separation = get_theme_constant(SNAME("vseparation"), SNAME("ItemList"));
+ int separation = get_theme_constant(SNAME("v_separation"), SNAME("ItemList"));
return Vector2(0, MAX(font->get_height(font_size), icon->get_height()) + separation);
}
@@ -3290,7 +3409,7 @@ void AnimationTrackEditor::remove_track_edit_plugin(const Ref<AnimationTrackEdit
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) {
track_edits[_get_track_selected()]->release_focus();
}
@@ -3299,7 +3418,8 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &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();
@@ -3308,7 +3428,7 @@ void AnimationTrackEditor::set_animation(const Ref<Animation> &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();
@@ -3353,7 +3473,7 @@ Ref<Animation> AnimationTrackEditor::get_current_animation() const {
return animation;
}
-void AnimationTrackEditor::_root_removed(Node *p_root) {
+void AnimationTrackEditor::_root_removed() {
root = nullptr;
}
@@ -3365,7 +3485,7 @@ void AnimationTrackEditor::set_root(Node *p_root) {
root = p_root;
if (root) {
- root->connect("tree_exiting", callable_mp(this, &AnimationTrackEditor::_root_removed), make_binds(), CONNECT_ONESHOT);
+ root->connect("tree_exiting", callable_mp(this, &AnimationTrackEditor::_root_removed), CONNECT_ONESHOT);
}
_update_tracks();
@@ -3378,7 +3498,7 @@ Node *AnimationTrackEditor::get_root() const {
void AnimationTrackEditor::update_keying() {
bool keying_enabled = false;
- EditorHistory *editor_history = EditorNode::get_singleton()->get_editor_history();
+ EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
if (is_visible_in_tree() && animation.is_valid() && editor_history->get_path_size() > 0) {
Object *obj = ObjectDB::get_instance(editor_history->get_path_object(0));
keying_enabled = Object::cast_to<Node>(obj) != nullptr;
@@ -3437,7 +3557,7 @@ void AnimationTrackEditor::set_state(const Dictionary &p_state) {
}
void AnimationTrackEditor::cleanup() {
- set_animation(Ref<Animation>());
+ set_animation(Ref<Animation>(), read_only);
}
void AnimationTrackEditor::_name_limit_changed() {
@@ -3451,31 +3571,75 @@ void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag, bool
}
void AnimationTrackEditor::_track_remove_request(int p_track) {
- if (animation->track_is_compressed(p_track)) {
+ _animation_track_remove_request(p_track, animation);
+}
+
+void AnimationTrackEditor::_animation_track_remove_request(int p_track, Ref<Animation> p_from_animation) {
+ if (p_from_animation->track_is_compressed(p_track)) {
EditorNode::get_singleton()->show_warning(TTR("Compressed tracks can't be edited or removed. Re-import the animation with compression disabled in order to edit."));
return;
}
int idx = p_track;
- if (idx >= 0 && idx < animation->get_track_count()) {
+ if (idx >= 0 && idx < p_from_animation->get_track_count()) {
undo_redo->create_action(TTR("Remove Anim Track"));
+
+ // Remove corresponding reset tracks if they are no longer needed.
+ AnimationPlayer *player = AnimationPlayerEditor::get_singleton()->get_player();
+ if (player->has_animation(SceneStringNames::get_singleton()->RESET)) {
+ Ref<Animation> reset = player->get_animation(SceneStringNames::get_singleton()->RESET);
+ if (reset != p_from_animation) {
+ for (int i = 0; i < reset->get_track_count(); i++) {
+ if (reset->track_get_path(i) == p_from_animation->track_get_path(p_track)) {
+ // Check if the reset track isn't used by other animations.
+ bool used = false;
+ List<StringName> animation_list;
+ player->get_animation_list(&animation_list);
+
+ for (const StringName &anim_name : animation_list) {
+ Ref<Animation> anim = player->get_animation(anim_name);
+ if (anim == p_from_animation || anim == reset) {
+ continue;
+ }
+
+ for (int j = 0; j < anim->get_track_count(); j++) {
+ if (anim->track_get_path(j) == reset->track_get_path(i)) {
+ used = true;
+ break;
+ }
+ }
+
+ if (used) {
+ break;
+ }
+ }
+
+ if (!used) {
+ _animation_track_remove_request(i, reset);
+ }
+ break;
+ }
+ }
+ }
+ }
+
undo_redo->add_do_method(this, "_clear_selection", false);
- undo_redo->add_do_method(animation.ptr(), "remove_track", idx);
- undo_redo->add_undo_method(animation.ptr(), "add_track", animation->track_get_type(idx), idx);
- undo_redo->add_undo_method(animation.ptr(), "track_set_path", idx, animation->track_get_path(idx));
+ undo_redo->add_do_method(p_from_animation.ptr(), "remove_track", idx);
+ undo_redo->add_undo_method(p_from_animation.ptr(), "add_track", p_from_animation->track_get_type(idx), idx);
+ undo_redo->add_undo_method(p_from_animation.ptr(), "track_set_path", idx, p_from_animation->track_get_path(idx));
// TODO interpolation.
- for (int i = 0; i < animation->track_get_key_count(idx); i++) {
- Variant v = animation->track_get_key_value(idx, i);
- float time = animation->track_get_key_time(idx, i);
- float trans = animation->track_get_key_transition(idx, i);
+ for (int i = 0; i < p_from_animation->track_get_key_count(idx); i++) {
+ Variant v = p_from_animation->track_get_key_value(idx, i);
+ float time = p_from_animation->track_get_key_time(idx, i);
+ float trans = p_from_animation->track_get_key_transition(idx, i);
- undo_redo->add_undo_method(animation.ptr(), "track_insert_key", idx, time, v);
- undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", idx, i, trans);
+ undo_redo->add_undo_method(p_from_animation.ptr(), "track_insert_key", idx, time, v);
+ undo_redo->add_undo_method(p_from_animation.ptr(), "track_set_key_transition", idx, i, trans);
}
- undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", idx, animation->track_get_interpolation_type(idx));
- if (animation->track_get_type(idx) == Animation::TYPE_VALUE) {
- undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", idx, animation->value_track_get_update_mode(idx));
+ undo_redo->add_undo_method(p_from_animation.ptr(), "track_set_interpolation_type", idx, p_from_animation->track_get_interpolation_type(idx));
+ if (p_from_animation->track_get_type(idx) == Animation::TYPE_VALUE) {
+ undo_redo->add_undo_method(p_from_animation.ptr(), "value_track_set_update_mode", idx, p_from_animation->value_track_get_update_mode(idx));
}
undo_redo->commit_action();
@@ -3577,7 +3741,7 @@ void AnimationTrackEditor::commit_insert_queue() {
}
}
- if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true)) && num_tracks > 0) {
+ if (bool(EDITOR_GET("editors/animation/confirm_insert_track")) && num_tracks > 0) {
// Potentially a new key, does not exist.
if (num_tracks == 1) {
// TRANSLATORS: %s will be replaced by a phrase describing the target of track.
@@ -3589,7 +3753,7 @@ void AnimationTrackEditor::commit_insert_queue() {
insert_confirm_bezier->set_visible(all_bezier);
insert_confirm_reset->set_visible(reset_allowed);
- insert_confirm->get_ok_button()->set_text(TTR("Create"));
+ insert_confirm->set_ok_button_text(TTR("Create"));
insert_confirm->popup_centered();
} else {
_insert_track(reset_allowed && EDITOR_GET("editors/animation/default_create_reset_tracks"), all_bezier && EDITOR_GET("editors/animation/default_create_bezier_tracks"));
@@ -3618,11 +3782,11 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
}
}
-void AnimationTrackEditor::_insert_track(bool p_create_reset, bool p_create_beziers) {
+void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_beziers) {
undo_redo->create_action(TTR("Anim Insert"));
Ref<Animation> reset_anim;
- if (p_create_reset) {
+ if (p_reset_wanted) {
reset_anim = _create_and_get_reset_animation();
}
@@ -3632,26 +3796,14 @@ void AnimationTrackEditor::_insert_track(bool p_create_reset, bool p_create_bezi
if (insert_data.front()->get().advance) {
advance = true;
}
- next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, p_create_reset, reset_anim, p_create_beziers);
+ next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, p_reset_wanted, reset_anim, p_create_beziers);
insert_data.pop_front();
}
undo_redo->commit_action();
if (advance) {
- float step = animation->get_step();
- if (step == 0) {
- step = 1;
- }
-
- float pos = timeline->get_play_position();
-
- pos = Math::snapped(pos + step, step);
- if (pos > animation->get_length()) {
- pos = animation->get_length();
- }
- set_anim_pos(pos);
- emit_signal(SNAME("timeline_changed"), pos, true, false);
+ _edit_menu_pressed(EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY);
}
}
@@ -3771,7 +3923,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
return;
}
- EditorHistory *history = EditorNode::get_singleton()->get_editor_history();
+ EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history();
for (int i = 1; i < history->get_path_size(); i++) {
String prop = history->get_path_property(i);
ERR_FAIL_COND(prop.is_empty());
@@ -3851,7 +4003,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
}
void AnimationTrackEditor::insert_value_key(const String &p_property, const Variant &p_value, bool p_advance) {
- EditorHistory *history = EditorNode::get_singleton()->get_editor_history();
+ EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history();
ERR_FAIL_COND(!root);
// Let's build a node path.
@@ -3950,12 +4102,20 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
if (player->has_animation(SceneStringNames::get_singleton()->RESET)) {
return player->get_animation(SceneStringNames::get_singleton()->RESET);
} else {
+ Ref<AnimationLibrary> al;
+ if (!player->has_animation_library("")) {
+ al.instantiate();
+ player->add_animation_library("", al);
+ } else {
+ al = player->get_animation_library("");
+ }
+
Ref<Animation> reset_anim;
reset_anim.instantiate();
reset_anim->set_length(ANIM_MIN_LENGTH);
- undo_redo->add_do_method(player, "add_animation", SceneStringNames::get_singleton()->RESET, reset_anim);
+ undo_redo->add_do_method(al.ptr(), "add_animation", SceneStringNames::get_singleton()->RESET, reset_anim);
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player);
- undo_redo->add_undo_method(player, "remove_animation", SceneStringNames::get_singleton()->RESET);
+ undo_redo->add_undo_method(al.ptr(), "remove_animation", SceneStringNames::get_singleton()->RESET);
undo_redo->add_undo_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player);
return reset_anim;
}
@@ -3971,12 +4131,20 @@ void AnimationTrackEditor::_confirm_insert_list() {
}
TrackIndices next_tracks(animation.ptr(), reset_anim.ptr());
+ bool advance = false;
while (insert_data.size()) {
+ if (insert_data.front()->get().advance) {
+ advance = true;
+ }
next_tracks = _confirm_insert(insert_data.front()->get(), next_tracks, create_reset, reset_anim, insert_confirm_bezier->is_pressed());
insert_data.pop_front();
}
undo_redo->commit_action();
+
+ if (advance) {
+ _edit_menu_pressed(EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY);
+ }
}
PropertyInfo AnimationTrackEditor::_find_hint_for_track(int p_idx, NodePath &r_base_path, Variant *r_current_val) {
@@ -3994,7 +4162,7 @@ PropertyInfo AnimationTrackEditor::_find_hint_for_track(int p_idx, NodePath &r_b
return PropertyInfo();
}
- RES res;
+ Ref<Resource> res;
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(path, res, leftover_path, true);
@@ -4092,9 +4260,42 @@ static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool
return subindices;
}
-AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_create_reset, Ref<Animation> p_reset_anim, bool p_create_beziers) {
+AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertData p_id, TrackIndices p_next_tracks, bool p_reset_wanted, Ref<Animation> p_reset_anim, bool p_create_beziers) {
bool created = false;
- if (p_id.track_idx < 0) {
+
+ bool create_normal_track = p_id.track_idx < 0;
+ bool create_reset_track = p_reset_wanted && track_type_is_resettable(p_id.type);
+
+ Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
+ if (create_normal_track || create_reset_track) {
+ if (p_id.type == Animation::TYPE_VALUE || p_id.type == Animation::TYPE_BEZIER) {
+ // Hack.
+ NodePath np;
+ animation->add_track(p_id.type);
+ animation->track_set_path(animation->get_track_count() - 1, p_id.path);
+ PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
+ animation->remove_track(animation->get_track_count() - 1); // Hack.
+
+ if (h.type == Variant::FLOAT ||
+ h.type == Variant::VECTOR2 ||
+ h.type == Variant::RECT2 ||
+ h.type == Variant::VECTOR3 ||
+ h.type == Variant::AABB ||
+ h.type == Variant::QUATERNION ||
+ h.type == Variant::COLOR ||
+ h.type == Variant::PLANE ||
+ h.type == Variant::TRANSFORM2D ||
+ h.type == Variant::TRANSFORM3D) {
+ update_mode = Animation::UPDATE_CONTINUOUS;
+ }
+
+ if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) {
+ update_mode = Animation::UPDATE_TRIGGER;
+ }
+ }
+ }
+
+ if (create_normal_track) {
if (p_create_beziers) {
bool valid;
Vector<String> subindices = _get_bezier_subindices_for_type(p_id.value.get_type(), &valid);
@@ -4104,7 +4305,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
id.type = Animation::TYPE_BEZIER;
id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length()));
id.path = String(p_id.path) + subindices[i];
- p_next_tracks = _confirm_insert(id, p_next_tracks, p_create_reset, p_reset_anim, false);
+ p_next_tracks = _confirm_insert(id, p_next_tracks, p_reset_wanted, p_reset_anim, false);
}
return p_next_tracks;
@@ -4112,37 +4313,6 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
}
created = true;
undo_redo->create_action(TTR("Anim Insert Track & Key"));
- Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
-
- if (p_id.type == Animation::TYPE_VALUE || p_id.type == Animation::TYPE_BEZIER) {
- // Wants a new track.
-
- {
- // Hack.
- NodePath np;
- animation->add_track(p_id.type);
- animation->track_set_path(animation->get_track_count() - 1, p_id.path);
- PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
- animation->remove_track(animation->get_track_count() - 1); // Hack.
-
- if (h.type == Variant::FLOAT ||
- h.type == Variant::VECTOR2 ||
- h.type == Variant::RECT2 ||
- h.type == Variant::VECTOR3 ||
- h.type == Variant::AABB ||
- h.type == Variant::QUATERNION ||
- h.type == Variant::COLOR ||
- h.type == Variant::PLANE ||
- h.type == Variant::TRANSFORM2D ||
- h.type == Variant::TRANSFORM3D) {
- update_mode = Animation::UPDATE_CONTINUOUS;
- }
-
- if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) {
- update_mode = Animation::UPDATE_TRIGGER;
- }
- }
- }
p_id.track_idx = p_next_tracks.normal;
@@ -4205,8 +4375,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
}
}
- if (p_create_reset && track_type_is_resettable(p_id.type)) {
- bool create_reset_track = true;
+ if (create_reset_track) {
Animation *reset_anim = p_reset_anim.ptr();
for (int i = 0; i < reset_anim->get_track_count(); i++) {
if (reset_anim->track_get_path(i) == p_id.path) {
@@ -4217,6 +4386,9 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
if (create_reset_track) {
undo_redo->add_do_method(reset_anim, "add_track", p_id.type);
undo_redo->add_do_method(reset_anim, "track_set_path", p_next_tracks.reset, p_id.path);
+ if (p_id.type == Animation::TYPE_VALUE) {
+ undo_redo->add_do_method(reset_anim, "value_track_set_update_mode", p_next_tracks.reset, update_mode);
+ }
undo_redo->add_do_method(reset_anim, "track_insert_key", p_next_tracks.reset, 0.0f, value);
undo_redo->add_undo_method(reset_anim, "remove_track", reset_anim->get_track_count());
p_next_tracks.reset++;
@@ -4262,7 +4434,28 @@ void AnimationTrackEditor::_update_tracks() {
return;
}
- Map<String, VBoxContainer *> group_sort;
+ 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;
bool use_grouping = !view_group->is_pressed();
bool use_filter = selected_filter->is_pressed();
@@ -4290,7 +4483,7 @@ void AnimationTrackEditor::_update_tracks() {
NodePath path = animation->track_get_path(i);
if (root && root->has_node_and_resource(path)) {
- RES res;
+ Ref<Resource> res;
NodePath base_path;
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(path, res, leftover_path, true);
@@ -4390,7 +4583,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);
@@ -4399,20 +4592,20 @@ void AnimationTrackEditor::_update_tracks() {
}
track_edit->connect("timeline_changed", callable_mp(this, &AnimationTrackEditor::_timeline_changed));
- track_edit->connect("remove_request", callable_mp(this, &AnimationTrackEditor::_track_remove_request), varray(), CONNECT_DEFERRED);
- track_edit->connect("dropped", callable_mp(this, &AnimationTrackEditor::_dropped_track), varray(), CONNECT_DEFERRED);
- track_edit->connect("insert_key", callable_mp(this, &AnimationTrackEditor::_insert_key_from_track), varray(i), CONNECT_DEFERRED);
- track_edit->connect("select_key", callable_mp(this, &AnimationTrackEditor::_key_selected), varray(i), CONNECT_DEFERRED);
- track_edit->connect("deselect_key", callable_mp(this, &AnimationTrackEditor::_key_deselected), varray(i), CONNECT_DEFERRED);
+ track_edit->connect("remove_request", callable_mp(this, &AnimationTrackEditor::_track_remove_request), CONNECT_DEFERRED);
+ track_edit->connect("dropped", callable_mp(this, &AnimationTrackEditor::_dropped_track), CONNECT_DEFERRED);
+ track_edit->connect("insert_key", callable_mp(this, &AnimationTrackEditor::_insert_key_from_track).bind(i), CONNECT_DEFERRED);
+ track_edit->connect("select_key", callable_mp(this, &AnimationTrackEditor::_key_selected).bind(i), CONNECT_DEFERRED);
+ track_edit->connect("deselect_key", callable_mp(this, &AnimationTrackEditor::_key_deselected).bind(i), CONNECT_DEFERRED);
track_edit->connect("move_selection_begin", callable_mp(this, &AnimationTrackEditor::_move_selection_begin));
track_edit->connect("move_selection", callable_mp(this, &AnimationTrackEditor::_move_selection));
track_edit->connect("move_selection_commit", callable_mp(this, &AnimationTrackEditor::_move_selection_commit));
track_edit->connect("move_selection_cancel", callable_mp(this, &AnimationTrackEditor::_move_selection_cancel));
- track_edit->connect("duplicate_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_DUPLICATE_SELECTION), CONNECT_DEFERRED);
- track_edit->connect("duplicate_transpose_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_DUPLICATE_TRANSPOSED), CONNECT_DEFERRED);
- track_edit->connect("create_reset_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_ADD_RESET_KEY), CONNECT_DEFERRED);
- track_edit->connect("delete_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_DELETE_SELECTION), CONNECT_DEFERRED);
+ track_edit->connect("duplicate_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_DUPLICATE_SELECTION), CONNECT_DEFERRED);
+ track_edit->connect("duplicate_transpose_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_DUPLICATE_TRANSPOSED), CONNECT_DEFERRED);
+ track_edit->connect("create_reset_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_ADD_RESET_KEY), CONNECT_DEFERRED);
+ track_edit->connect("delete_request", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_DELETE_SELECTION), CONNECT_DEFERRED);
}
}
@@ -4513,27 +4706,33 @@ MenuButton *AnimationTrackEditor::get_edit_menu() {
}
void AnimationTrackEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE || p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
- panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
- }
+ switch (p_what) {
+ case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ } break;
- if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
- zoom_icon->set_texture(get_theme_icon(SNAME("Zoom"), SNAME("EditorIcons")));
- bezier_edit_icon->set_icon(get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")));
- snap->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
- view_group->set_icon(get_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"), SNAME("EditorIcons")));
- selected_filter->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
- imported_anim_warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
- main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
- edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
- }
+ case NOTIFICATION_ENTER_TREE: {
+ panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EditorSettings::get_singleton()->get("editors/panning/simple_panning")));
+ [[fallthrough]];
+ }
+ case NOTIFICATION_THEME_CHANGED: {
+ zoom_icon->set_texture(get_theme_icon(SNAME("Zoom"), SNAME("EditorIcons")));
+ bezier_edit_icon->set_icon(get_theme_icon(SNAME("EditBezier"), SNAME("EditorIcons")));
+ snap->set_icon(get_theme_icon(SNAME("Snap"), SNAME("EditorIcons")));
+ view_group->set_icon(get_theme_icon(view_group->is_pressed() ? SNAME("AnimationTrackList") : SNAME("AnimationTrackGroup"), SNAME("EditorIcons")));
+ selected_filter->set_icon(get_theme_icon(SNAME("AnimationFilter"), SNAME("EditorIcons")));
+ imported_anim_warning->set_icon(get_theme_icon(SNAME("NodeWarning"), SNAME("EditorIcons")));
+ main_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));
+ edit->get_popup()->set_item_icon(edit->get_popup()->get_item_index(EDIT_APPLY_RESET), get_theme_icon(SNAME("Reload"), SNAME("EditorIcons")));
+ } break;
- if (p_what == NOTIFICATION_READY) {
- EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &AnimationTrackEditor::_selection_changed));
- }
+ case NOTIFICATION_READY: {
+ EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", callable_mp(this, &AnimationTrackEditor::_selection_changed));
+ } break;
- if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- update_keying();
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ update_keying();
+ } break;
}
}
@@ -4890,7 +5089,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
} break;
case Animation::TYPE_AUDIO: {
Dictionary ak;
- ak["stream"] = RES();
+ ak["stream"] = Ref<Resource>();
ak["start_offset"] = 0;
ak["end_offset"] = 0;
@@ -4949,7 +5148,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
}
}
- EditorNode::get_singleton()->show_warning(TTR("Method not found in object: ") + p_method);
+ EditorNode::get_singleton()->show_warning(TTR("Method not found in object:") + " " + p_method);
}
void AnimationTrackEditor::_key_selected(int p_key, bool p_single, int p_track) {
@@ -5056,6 +5255,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();
@@ -5072,9 +5272,10 @@ 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;
- Map<int, List<float>> key_ofs_map;
- Map<int, NodePath> base_map;
+ RBMap<int, List<float>> key_ofs_map;
+ RBMap<int, NodePath> base_map;
int first_track = -1;
for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
int track = E.key.track;
@@ -5135,11 +5336,11 @@ void AnimationTrackEditor::_move_selection_commit() {
float motion = moving_selection_offset;
// 1 - remove the keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
}
// 2 - Remove overlapped keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newtime = snap_time(E->get().pos + motion);
int idx = animation->track_find_key(E->key().track, newtime, true);
if (idx == -1) {
@@ -5164,19 +5365,19 @@ void AnimationTrackEditor::_move_selection_commit() {
}
// 3 - Move the keys (Reinsert them).
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = snap_time(E->get().pos + motion);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
}
// 4 - (Undo) Remove inserted keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = snap_time(E->get().pos + motion);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}
// 5 - (Undo) Reinsert keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
}
@@ -5189,7 +5390,7 @@ void AnimationTrackEditor::_move_selection_commit() {
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
// 7 - Reselect.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float oldpos = E->get().pos;
float newpos = snap_time(oldpos + motion);
@@ -5332,11 +5533,14 @@ void AnimationTrackEditor::_pan_callback(Vector2 p_scroll_vec) {
}
void AnimationTrackEditor::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
- if (p_scroll_vec.y < 0) {
- timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
+ double new_zoom_value;
+ double current_zoom_value = timeline->get_zoom()->get_value();
+ if (current_zoom_value <= 0.1) {
+ new_zoom_value = MAX(0.01, current_zoom_value - 0.01 * SIGN(p_scroll_vec.y));
} else {
- timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
+ new_zoom_value = p_scroll_vec.y > 0 ? MAX(0.01, current_zoom_value / 1.05) : current_zoom_value * 1.05;
}
+ timeline->get_zoom()->set_value(new_zoom_value);
}
void AnimationTrackEditor::_cancel_bezier_edit() {
@@ -5348,7 +5552,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.
@@ -5359,7 +5563,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) {
int top_track = 0x7FFFFFFF;
float top_time = 1e10;
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
const SelectedKey &sk = E->key();
float t = animation->track_get_key_time(sk.track, sk.key);
@@ -5380,7 +5584,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
List<Pair<int, float>> new_selection_values;
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
const SelectedKey &sk = E->key();
float t = animation->track_get_key_time(sk.track, sk.key);
@@ -5415,7 +5619,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
// Reselect duplicated.
- Map<SelectedKey, KeyInfo> new_selection;
+ RBMap<SelectedKey, KeyInfo> new_selection;
for (const Pair<int, float> &E : new_selection_values) {
int track = E.first;
float time = E.second;
@@ -5469,7 +5673,7 @@ void AnimationTrackEditor::goto_prev_step(bool p_from_mouse_event) {
emit_signal(SNAME("timeline_changed"), pos, true, false);
}
-void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event) {
+void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event, bool p_timeline_only) {
if (animation.is_null()) {
return;
}
@@ -5493,7 +5697,7 @@ void AnimationTrackEditor::goto_next_step(bool p_from_mouse_event) {
}
set_anim_pos(pos);
- emit_signal(SNAME("timeline_changed"), pos, true, false);
+ emit_signal(SNAME("timeline_changed"), pos, true, p_timeline_only);
}
void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
@@ -5534,31 +5738,35 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
}
+ String track_type;
switch (animation->track_get_type(i)) {
case Animation::TYPE_POSITION_3D:
- text += " (Position)";
+ track_type = TTR("Position");
break;
case Animation::TYPE_ROTATION_3D:
- text += " (Rotation)";
+ track_type = TTR("Rotation");
break;
case Animation::TYPE_SCALE_3D:
- text += " (Scale)";
+ track_type = TTR("Scale");
break;
case Animation::TYPE_BLEND_SHAPE:
- text += " (BlendShape)";
+ track_type = TTR("BlendShape");
break;
case Animation::TYPE_METHOD:
- text += " (Methods)";
+ track_type = TTR("Methods");
break;
case Animation::TYPE_BEZIER:
- text += " (Bezier)";
+ track_type = TTR("Bezier");
break;
case Animation::TYPE_AUDIO:
- text += " (Audio)";
+ track_type = TTR("Audio");
break;
default: {
};
}
+ if (!track_type.is_empty()) {
+ text += vformat(" (%s)", track_type);
+ }
TreeItem *it = track_copy_select->create_item(troot);
it->set_editable(0, true);
@@ -5689,11 +5897,11 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
List<_AnimMoveRestore> to_restore;
// 1 - Remove the keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
}
// 2 - Remove overlapped keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newtime = (E->get().pos - from_t) * s + from_t;
int idx = animation->track_find_key(E->key().track, newtime, true);
if (idx == -1) {
@@ -5719,19 +5927,19 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
#define NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * ABS(s) + from_t
// 3 - Move the keys (re insert them).
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = NEW_POS(E->get().pos);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
}
// 4 - (Undo) Remove inserted keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float newpos = NEW_POS(E->get().pos);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->key().track, newpos);
}
// 5 - (Undo) Reinsert keys.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
}
@@ -5744,7 +5952,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
// 7-reselect.
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
float oldpos = E->get().pos;
float newpos = NEW_POS(oldpos);
if (newpos >= 0) {
@@ -5773,7 +5981,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->create_action(TTR("Anim Add RESET Keys"));
Ref<Animation> reset = _create_and_get_reset_animation();
int reset_tracks = reset->get_track_count();
- Set<int> tracks_added;
+ HashSet<int> tracks_added;
for (const KeyValue<SelectedKey, KeyInfo> &E : selection) {
const SelectedKey &sk = E.key;
@@ -5827,7 +6035,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
if (selection.size()) {
undo_redo->create_action(TTR("Anim Delete Keys"));
- for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
+ for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
}
@@ -5837,8 +6045,9 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
_update_key_edit();
}
} break;
+ case EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY:
case EDIT_GOTO_NEXT_STEP: {
- goto_next_step(false);
+ goto_next_step(false, p_option == EDIT_GOTO_NEXT_STEP_TIMELINE_ONLY);
} break;
case EDIT_GOTO_PREV_STEP: {
goto_prev_step(false);
@@ -5882,7 +6091,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
Variant::Type valid_type = Variant::NIL;
Object *obj = nullptr;
- RES res;
+ Ref<Resource> res;
Vector<StringName> leftover_path;
Node *node = root->get_node_and_resource(p_animation->track_get_path(i), res, leftover_path);
@@ -5981,7 +6190,8 @@ float AnimationTrackEditor::snap_time(float p_value, bool p_relative) {
void AnimationTrackEditor::_show_imported_anim_warning() {
// It looks terrible on a single line but the TTR extractor doesn't support line breaks yet.
- EditorNode::get_singleton()->show_warning(TTR("This animation belongs to an imported scene, so changes to imported tracks will not be saved.\n\nTo enable the ability to add custom tracks, navigate to the scene's import settings and set\n\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks\", then re-import.\nAlternatively, use an import preset that imports animations to separate files."),
+ EditorNode::get_singleton()->show_warning(
+ TTR("This animation belongs to an imported scene, so changes to imported tracks will not be saved.\n\nTo modify this animation, navigate to the scene's Advanced Import settings and select the animation.\nSome options, including looping, are available here. To add custom tracks, enable \"Save To File\" and\n\"Keep Custom Tracks\"."),
TTR("Warning: Editing imported animation"));
}
@@ -6091,8 +6301,6 @@ void AnimationTrackEditor::_pick_track_filter_input(const Ref<InputEvent> &p_ie)
}
AnimationTrackEditor::AnimationTrackEditor() {
- root = nullptr;
-
undo_redo = EditorNode::get_singleton()->get_undo_redo();
main_panel = memnew(PanelContainer);
@@ -6113,9 +6321,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
info_message->set_text(TTR("Select an AnimationPlayer node to create and edit animations."));
info_message->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
info_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
- info_message->set_autowrap_mode(Label::AUTOWRAP_WORD_SMART);
+ info_message->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
info_message->set_custom_minimum_size(Size2(100 * EDSCALE, 0));
- info_message->set_anchors_and_offsets_preset(PRESET_WIDE, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
+ info_message->set_anchors_and_offsets_preset(PRESET_FULL_RECT, PRESET_MODE_KEEP_SIZE, 8 * EDSCALE);
main_panel->add_child(info_message);
timeline = memnew(AnimationTimelineEdit);
@@ -6169,6 +6377,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
imported_anim_warning = memnew(Button);
imported_anim_warning->hide();
+ imported_anim_warning->set_text(TTR("Imported Scene"));
imported_anim_warning->set_tooltip(TTR("Warning: Editing imported animation"));
imported_anim_warning->connect("pressed", callable_mp(this, &AnimationTrackEditor::_show_imported_anim_warning));
bottom_hb->add_child(imported_anim_warning);
@@ -6288,8 +6497,6 @@ AnimationTrackEditor::AnimationTrackEditor() {
add_child(method_selector);
method_selector->connect("selected", callable_mp(this, &AnimationTrackEditor::_add_method_key));
- insert_queue = false;
-
insert_confirm = memnew(ConfirmationDialog);
add_child(insert_confirm);
insert_confirm->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_confirm_insert_list));
@@ -6307,10 +6514,6 @@ AnimationTrackEditor::AnimationTrackEditor() {
insert_confirm_reset->set_text(TTR("Create RESET Track(s)", ""));
insert_confirm_reset->set_pressed(EDITOR_GET("editors/animation/default_create_reset_tracks"));
ichb->add_child(insert_confirm_reset);
- keying = false;
- moving_selection = false;
- key_edit = nullptr;
- multi_key_edit = nullptr;
box_selection = memnew(Control);
add_child(box_selection);
@@ -6318,7 +6521,6 @@ AnimationTrackEditor::AnimationTrackEditor() {
box_selection->set_mouse_filter(MOUSE_FILTER_IGNORE);
box_selection->hide();
box_selection->connect("draw", callable_mp(this, &AnimationTrackEditor::_box_selection_draw));
- box_selecting = false;
// Default Plugins.
@@ -6354,8 +6556,8 @@ AnimationTrackEditor::AnimationTrackEditor() {
optimize_max_angle->set_step(0.1);
optimize_max_angle->set_value(22);
- optimize_dialog->get_ok_button()->set_text(TTR("Optimize"));
- optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_OPTIMIZE_ANIMATION_CONFIRM));
+ optimize_dialog->set_ok_button_text(TTR("Optimize"));
+ optimize_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_OPTIMIZE_ANIMATION_CONFIRM));
//
@@ -6379,9 +6581,9 @@ AnimationTrackEditor::AnimationTrackEditor() {
cleanup_vb->add_child(cleanup_all);
cleanup_dialog->set_title(TTR("Clean-Up Animation(s) (NO UNDO!)"));
- cleanup_dialog->get_ok_button()->set_text(TTR("Clean-Up"));
+ cleanup_dialog->set_ok_button_text(TTR("Clean-Up"));
- cleanup_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
+ cleanup_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
//
scale_dialog = memnew(ConfirmationDialog);
@@ -6393,13 +6595,13 @@ AnimationTrackEditor::AnimationTrackEditor() {
scale->set_max(99999);
scale->set_step(0.001);
vbc->add_margin_child(TTR("Scale Ratio:"), scale);
- scale_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_SCALE_CONFIRM));
+ scale_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_SCALE_CONFIRM));
add_child(scale_dialog);
track_copy_dialog = memnew(ConfirmationDialog);
add_child(track_copy_dialog);
track_copy_dialog->set_title(TTR("Select Tracks to Copy"));
- track_copy_dialog->get_ok_button()->set_text(TTR("Copy"));
+ track_copy_dialog->set_ok_button_text(TTR("Copy"));
VBoxContainer *track_vbox = memnew(VBoxContainer);
track_copy_dialog->add_child(track_vbox);
@@ -6414,8 +6616,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
track_copy_select->set_v_size_flags(SIZE_EXPAND_FILL);
track_copy_select->set_hide_root(true);
track_vbox->add_child(track_copy_select);
- track_copy_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed), varray(EDIT_COPY_TRACKS_CONFIRM));
- animation_changing_awaiting_update = false;
+ track_copy_dialog->connect("confirmed", callable_mp(this, &AnimationTrackEditor::_edit_menu_pressed).bind(EDIT_COPY_TRACKS_CONFIRM));
}
AnimationTrackEditor::~AnimationTrackEditor() {