Add inspector plugin for key time edit & Change find key argument

This commit is contained in:
Silc Renew 2022-12-08 21:38:01 +09:00
parent 291add339f
commit 060fb2d093
19 changed files with 1537 additions and 1411 deletions

View File

@ -305,9 +305,9 @@
<return type="int" /> <return type="int" />
<param index="0" name="track_idx" type="int" /> <param index="0" name="track_idx" type="int" />
<param index="1" name="time" type="float" /> <param index="1" name="time" type="float" />
<param index="2" name="exact" type="bool" default="false" /> <param index="2" name="find_mode" type="int" enum="Animation.FindMode" default="0" />
<description> <description>
Finds the key index by time in a given track. Optionally, only find it if the exact time is given. Finds the key index by time in a given track. Optionally, only find it if the approx/exact time is given.
</description> </description>
</method> </method>
<method name="track_get_interpolation_loop_wrap" qualifiers="const"> <method name="track_get_interpolation_loop_wrap" qualifiers="const">
@ -622,5 +622,14 @@
<constant name="LOOPED_FLAG_START" value="2" enum="LoopedFlag"> <constant name="LOOPED_FLAG_START" value="2" enum="LoopedFlag">
This flag indicates that the animation has reached the start of the animation and just after loop processed. This flag indicates that the animation has reached the start of the animation and just after loop processed.
</constant> </constant>
<constant name="FIND_MODE_NEAREST" value="0" enum="FindMode">
Finds the nearest time key.
</constant>
<constant name="FIND_MODE_APPROX" value="1" enum="FindMode">
Finds only the key with approximating the time.
</constant>
<constant name="FIND_MODE_EXACT" value="2" enum="FindMode">
Finds only the key with matching the time.
</constant>
</constants> </constants>
</class> </class>

View File

@ -28,4 +28,26 @@
The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed. The suffix to display after the value (in a faded color). This should generally be a plural word. You may have to use an abbreviation if the suffix is too long to be displayed.
</member> </member>
</members> </members>
<signals>
<signal name="grabbed">
<description>
Emitted when the spinner/slider is grabbed.
</description>
</signal>
<signal name="ungrabbed">
<description>
Emitted when the spinner/slider is ungrabbed.
</description>
</signal>
<signal name="value_focus_entered">
<description>
Emitted when the value form gains focus.
</description>
</signal>
<signal name="value_focus_exited">
<description>
Emitted when the value form loses focus.
</description>
</signal>
</signals>
</class> </class>

View File

@ -575,7 +575,7 @@ void AnimationBezierTrackEdit::_notification(int p_what) {
ep.point_rect.size = bezier_icon->get_size(); ep.point_rect.size = bezier_icon->get_size();
if (selection.has(IntPair(i, j))) { if (selection.has(IntPair(i, j))) {
draw_texture(selected_icon, ep.point_rect.position); draw_texture(selected_icon, ep.point_rect.position);
draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent); draw_string(font, ep.point_rect.position + Vector2(8, -font->get_height(font_size) - 8), TTR("Time:") + " " + TS->format_number(rtos(Math::snapped(offset, 0.0001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent); draw_string(font, ep.point_rect.position + Vector2(8, -8), TTR("Value:") + " " + TS->format_number(rtos(Math::snapped(value, 0.001))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, accent);
} else { } else {
Color track_color = Color(1, 1, 1, 1); Color track_color = Color(1, 1, 1, 1);
@ -812,7 +812,7 @@ void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int
return; return;
} }
int idx = animation->track_find_key(p_track, p_pos, true); int idx = animation->track_find_key(p_track, p_pos, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(idx < 0); ERR_FAIL_COND(idx < 0);
selection.insert(IntPair(p_track, idx)); selection.insert(IntPair(p_track, idx));
@ -1168,8 +1168,8 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
new_point[4] = 0; new_point[4] = 0;
real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(selected_track, time, true) != -1) { while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) {
time += 0.001; time += 0.0001;
} }
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
@ -1179,7 +1179,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
undo_redo->commit_action(); undo_redo->commit_action();
//then attempt to move //then attempt to move
int index = animation->track_find_key(selected_track, time, true); int index = animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(index == -1); ERR_FAIL_COND(index == -1);
_clear_selection(); _clear_selection();
selection.insert(IntPair(selected_track, index)); selection.insert(IntPair(selected_track, index));
@ -1283,7 +1283,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x); real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
int idx = animation->track_find_key(E->get().first, newtime, true); int idx = animation->track_find_key(E->get().first, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) { if (idx == -1) {
continue; continue;
} }
@ -1539,7 +1539,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value(); real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
while (animation->track_find_key(selected_track, time, true) != -1) { while (animation->track_find_key(selected_track, time, Animation::FIND_MODE_APPROX) != -1) {
time += 0.001; time += 0.001;
} }
@ -1599,7 +1599,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) { for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
real_t t = animation->track_get_key_time(E->get().first, E->get().second); real_t t = animation->track_get_key_time(E->get().first, E->get().second);
real_t dst_time = t + (timeline->get_play_position() - top_time); real_t dst_time = t + (timeline->get_play_position() - top_time);
int existing_idx = animation->track_find_key(E->get().first, dst_time, true); int existing_idx = animation->track_find_key(E->get().first, dst_time, Animation::FIND_MODE_APPROX);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second)); undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, E->get().second), animation->track_get_key_transition(E->get().first, E->get().second));
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time);
@ -1623,7 +1623,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
int track = E.first; int track = E.first;
real_t time = E.second; real_t time = E.second;
int existing_idx = animation->track_find_key(track, time, true); int existing_idx = animation->track_find_key(track, time, Animation::FIND_MODE_APPROX);
if (existing_idx == -1) { if (existing_idx == -1) {
continue; continue;

View File

@ -48,22 +48,7 @@
#include "scene/scene_string_names.h" #include "scene/scene_string_names.h"
#include "servers/audio/audio_stream.h" #include "servers/audio/audio_stream.h"
class AnimationTrackKeyEdit : public Object { void AnimationTrackKeyEdit::_bind_methods() {
GDCLASS(AnimationTrackKeyEdit, Object);
public:
bool setting = false;
bool animation_read_only = false;
bool _hide_script_from_inspector() { return true; }
bool _hide_metadata_from_inspector() { return true; }
bool _dont_undo_redo() { return true; }
bool _is_read_only() {
return animation_read_only;
}
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj); ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationTrackKeyEdit::_update_obj);
ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed); ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationTrackKeyEdit::_key_ofs_changed);
ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector); ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationTrackKeyEdit::_hide_script_from_inspector);
@ -71,9 +56,9 @@ public:
ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path); ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationTrackKeyEdit::get_root_path);
ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo); ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationTrackKeyEdit::_dont_undo_redo);
ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only); ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationTrackKeyEdit::_is_read_only);
} }
void _fix_node_path(Variant &value) { void AnimationTrackKeyEdit::_fix_node_path(Variant &value) {
NodePath np = value; NodePath np = value;
if (np == NodePath()) { if (np == NodePath()) {
@ -89,17 +74,17 @@ public:
ERR_FAIL_COND(!edited_node); ERR_FAIL_COND(!edited_node);
value = edited_node->get_path_to(np_node); value = edited_node->get_path_to(np_node);
} }
void _update_obj(const Ref<Animation> &p_anim) { void AnimationTrackKeyEdit::_update_obj(const Ref<Animation> &p_anim) {
if (setting || animation != p_anim) { if (setting || animation != p_anim) {
return; return;
} }
notify_change(); notify_change();
} }
void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) { void AnimationTrackKeyEdit::_key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
if (animation != p_anim || from != key_ofs) { if (animation != p_anim || from != key_ofs) {
return; return;
} }
@ -111,55 +96,13 @@ public:
} }
notify_change(); notify_change();
} }
bool _set(const StringName &p_name, const Variant &p_value) { bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_value) {
int key = animation->track_find_key(track, key_ofs, true); int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND_V(key == -1, false); ERR_FAIL_COND_V(key == -1, false);
String name = p_name; String name = p_name;
if (name == "time" || name == "frame") {
float new_time = p_value;
if (name == "frame") {
float fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
new_time /= fps;
}
if (new_time == key_ofs) {
return true;
}
int existing = animation->track_find_key(track, new_time, true);
setting = true;
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
Variant val = animation->track_get_key_value(track, key);
float trans = animation->track_get_key_transition(track, key);
undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
if (existing != -1) {
Variant v = animation->track_get_key_value(track, existing);
trans = animation->track_get_key_transition(track, existing);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans);
}
undo_redo->commit_action();
setting = false;
return true;
}
if (name == "easing") { if (name == "easing") {
float val = p_value; float val = p_value;
float prev_val = animation->track_get_key_transition(track, key); float prev_val = animation->track_get_key_transition(track, key);
@ -199,7 +142,7 @@ public:
} }
} }
undo_redo->create_action(vformat(TTR("Anim Change %s"), chan)); undo_redo->create_action(vformat(TTR("Animation Change %s"), chan));
undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value); undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old); undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
undo_redo->add_do_method(this, "_update_obj", animation); undo_redo->add_do_method(this, "_update_obj", animation);
@ -433,27 +376,13 @@ public:
} }
return false; return false;
} }
bool _get(const StringName &p_name, Variant &r_ret) const { bool AnimationTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const {
int key = animation->track_find_key(track, key_ofs, true); int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND_V(key == -1, false); ERR_FAIL_COND_V(key == -1, false);
String name = p_name; String name = p_name;
if (name == "time") {
r_ret = key_ofs;
return true;
}
if (name == "frame") {
float fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
r_ret = key_ofs * fps;
return true;
}
if (name == "easing") { if (name == "easing") {
r_ret = animation->track_get_key_transition(track, key); r_ret = animation->track_get_key_transition(track, key);
return true; return true;
@ -560,23 +489,17 @@ public:
} }
return false; return false;
} }
void _get_property_list(List<PropertyInfo> *p_list) const {
void AnimationTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
if (animation.is_null()) { if (animation.is_null()) {
return; return;
} }
ERR_FAIL_INDEX(track, animation->get_track_count()); ERR_FAIL_INDEX(track, animation->get_track_count());
int key = animation->track_find_key(track, key_ofs, true); int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(key == -1); ERR_FAIL_COND(key == -1);
if (use_fps && animation->get_step() > 0) {
float max_frame = animation->get_length() / animation->get_step();
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, PNAME("time"), PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
}
switch (animation->track_get_type(track)) { switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: { case Animation::TYPE_POSITION_3D: {
p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position"))); p_list->push_back(PropertyInfo(Variant::VECTOR3, PNAME("position")));
@ -654,8 +577,8 @@ public:
} break; } break;
case Animation::TYPE_AUDIO: { case Animation::TYPE_AUDIO: {
p_list->push_back(PropertyInfo(Variant::OBJECT, PNAME("stream"), PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); 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("start_offset"), PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater"));
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("end_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.0001,or_greater"));
} break; } break;
case Animation::TYPE_ANIMATION: { case Animation::TYPE_ANIMATION: {
@ -689,47 +612,22 @@ public:
if (animation->track_get_type(track) == Animation::TYPE_VALUE) { if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING)); p_list->push_back(PropertyInfo(Variant::FLOAT, PNAME("easing"), PROPERTY_HINT_EXP_EASING));
} }
} }
Ref<Animation> animation; void AnimationTrackKeyEdit::notify_change() {
int track = -1;
float key_ofs = 0;
Node *root_path = nullptr;
PropertyInfo hint;
NodePath base;
bool use_fps = false;
void notify_change() {
notify_property_list_changed(); notify_property_list_changed();
} }
Node *get_root_path() { Node *AnimationTrackKeyEdit::get_root_path() {
return root_path; return root_path;
} }
void set_use_fps(bool p_enable) { void AnimationTrackKeyEdit::set_use_fps(bool p_enable) {
use_fps = p_enable; use_fps = p_enable;
notify_property_list_changed(); notify_property_list_changed();
} }
};
class AnimationMultiTrackKeyEdit : public Object { void AnimationMultiTrackKeyEdit::_bind_methods() {
GDCLASS(AnimationMultiTrackKeyEdit, Object);
public:
bool setting = false;
bool animation_read_only = false;
bool _hide_script_from_inspector() { return true; }
bool _hide_metadata_from_inspector() { return true; }
bool _dont_undo_redo() { return true; }
bool _is_read_only() {
return animation_read_only;
}
static void _bind_methods() {
ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj); ClassDB::bind_method(D_METHOD("_update_obj"), &AnimationMultiTrackKeyEdit::_update_obj);
ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed); ClassDB::bind_method(D_METHOD("_key_ofs_changed"), &AnimationMultiTrackKeyEdit::_key_ofs_changed);
ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector); ClassDB::bind_method(D_METHOD("_hide_script_from_inspector"), &AnimationMultiTrackKeyEdit::_hide_script_from_inspector);
@ -737,9 +635,9 @@ public:
ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path); ClassDB::bind_method(D_METHOD("get_root_path"), &AnimationMultiTrackKeyEdit::get_root_path);
ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo); ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &AnimationMultiTrackKeyEdit::_dont_undo_redo);
ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only); ClassDB::bind_method(D_METHOD("_is_read_only"), &AnimationMultiTrackKeyEdit::_is_read_only);
} }
void _fix_node_path(Variant &value, NodePath &base) { void AnimationMultiTrackKeyEdit::_fix_node_path(Variant &value, NodePath &base) {
NodePath np = value; NodePath np = value;
if (np == NodePath()) { if (np == NodePath()) {
@ -755,17 +653,17 @@ public:
ERR_FAIL_COND(!edited_node); ERR_FAIL_COND(!edited_node);
value = edited_node->get_path_to(np_node); value = edited_node->get_path_to(np_node);
} }
void _update_obj(const Ref<Animation> &p_anim) { void AnimationMultiTrackKeyEdit::_update_obj(const Ref<Animation> &p_anim) {
if (setting || animation != p_anim) { if (setting || animation != p_anim) {
return; return;
} }
notify_change(); notify_change();
} }
void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) { void AnimationMultiTrackKeyEdit::_key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
if (animation != p_anim) { if (animation != p_anim) {
return; return;
} }
@ -790,53 +688,19 @@ public:
return; return;
} }
} }
} }
bool _set(const StringName &p_name, const Variant &p_value) { bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p_value) {
bool update_obj = false; bool update_obj = false;
bool change_notify_deserved = false; bool change_notify_deserved = false;
for (const KeyValue<int, List<float>> &E : key_ofs_map) { for (const KeyValue<int, List<float>> &E : key_ofs_map) {
int track = E.key; int track = E.key;
for (const float &key_ofs : E.value) { for (const float &key_ofs : E.value) {
int key = animation->track_find_key(track, key_ofs, true); int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND_V(key == -1, false); ERR_FAIL_COND_V(key == -1, false);
String name = p_name; String name = p_name;
if (name == "time" || name == "frame") { if (name == "easing") {
float new_time = p_value;
if (name == "frame") {
float fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
new_time /= fps;
}
int existing = animation->track_find_key(track, new_time, true);
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
if (!setting) {
setting = true;
undo_redo->create_action(TTR("Animation Multi Change Keyframe Time"), UndoRedo::MERGE_ENDS);
}
Variant val = animation->track_get_key_value(track, key);
float trans = animation->track_get_key_transition(track, key);
undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
if (existing != -1) {
Variant v = animation->track_get_key_value(track, existing);
trans = animation->track_get_key_transition(track, existing);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans);
}
} else if (name == "easing") {
float val = p_value; float val = p_value;
float prev_val = animation->track_get_key_transition(track, key); float prev_val = animation->track_get_key_transition(track, key);
@ -1079,30 +943,16 @@ public:
} }
return false; return false;
} }
bool _get(const StringName &p_name, Variant &r_ret) const { bool AnimationMultiTrackKeyEdit::_get(const StringName &p_name, Variant &r_ret) const {
for (const KeyValue<int, List<float>> &E : key_ofs_map) { for (const KeyValue<int, List<float>> &E : key_ofs_map) {
int track = E.key; int track = E.key;
for (const float &key_ofs : E.value) { for (const float &key_ofs : E.value) {
int key = animation->track_find_key(track, key_ofs, true); int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
ERR_CONTINUE(key == -1); ERR_CONTINUE(key == -1);
String name = p_name; String name = p_name;
if (name == "time") {
r_ret = key_ofs;
return true;
}
if (name == "frame") {
float fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
r_ret = key_ofs * fps;
return true;
}
if (name == "easing") { if (name == "easing") {
r_ret = animation->track_get_key_transition(track, key); r_ret = animation->track_get_key_transition(track, key);
return true; return true;
@ -1212,8 +1062,9 @@ public:
} }
return false; return false;
} }
void _get_property_list(List<PropertyInfo> *p_list) const {
void AnimationMultiTrackKeyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
if (animation.is_null()) { if (animation.is_null()) {
return; return;
} }
@ -1221,7 +1072,6 @@ public:
int first_track = -1; int first_track = -1;
float first_key = -1.0; float first_key = -1.0;
bool show_time = true;
bool same_track_type = true; bool same_track_type = true;
bool same_key_type = true; bool same_key_type = true;
for (const KeyValue<int, List<float>> &E : key_ofs_map) { for (const KeyValue<int, List<float>> &E : key_ofs_map) {
@ -1232,10 +1082,6 @@ public:
first_track = track; first_track = track;
} }
if (show_time && E.value.size() > 1) {
show_time = false;
}
if (same_track_type) { if (same_track_type) {
if (animation->track_get_type(first_track) != animation->track_get_type(track)) { if (animation->track_get_type(first_track) != animation->track_get_type(track)) {
same_track_type = false; same_track_type = false;
@ -1243,7 +1089,7 @@ public:
} }
for (const float &F : E.value) { for (const float &F : E.value) {
int key = animation->track_find_key(track, F, true); int key = animation->track_find_key(track, F, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(key == -1); ERR_FAIL_COND(key == -1);
if (first_key < 0) { if (first_key < 0) {
first_key = key; first_key = key;
@ -1256,15 +1102,6 @@ public:
} }
} }
if (show_time) {
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"));
} else {
p_list->push_back(PropertyInfo(Variant::FLOAT, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
}
}
if (same_track_type) { if (same_track_type) {
switch (animation->track_get_type(first_track)) { switch (animation->track_get_type(first_track)) {
case Animation::TYPE_POSITION_3D: { case Animation::TYPE_POSITION_3D: {
@ -1339,8 +1176,8 @@ public:
} break; } break;
case Animation::TYPE_AUDIO: { case Animation::TYPE_AUDIO: {
p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream")); 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, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.0001,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::FLOAT, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.0001,or_greater"));
} break; } break;
case Animation::TYPE_ANIMATION: { case Animation::TYPE_ANIMATION: {
if (key_ofs_map.size() > 1) { if (key_ofs_map.size() > 1) {
@ -1373,31 +1210,20 @@ public:
} break; } break;
} }
} }
} }
Ref<Animation> animation; void AnimationMultiTrackKeyEdit::notify_change() {
RBMap<int, List<float>> key_ofs_map;
RBMap<int, NodePath> base_map;
PropertyInfo hint;
Node *root_path = nullptr;
bool use_fps = false;
void notify_change() {
notify_property_list_changed(); notify_property_list_changed();
} }
Node *get_root_path() { Node *AnimationMultiTrackKeyEdit::get_root_path() {
return root_path; return root_path;
} }
void set_use_fps(bool p_enable) { void AnimationMultiTrackKeyEdit::set_use_fps(bool p_enable) {
use_fps = p_enable; use_fps = p_enable;
notify_property_list_changed(); notify_property_list_changed();
} }
};
void AnimationTimelineEdit::_zoom_changed(double) { void AnimationTimelineEdit::_zoom_changed(double) {
queue_redraw(); queue_redraw();
@ -1420,7 +1246,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
return; return;
} }
p_new_len = MAX(0.001, p_new_len); p_new_len = MAX(0.0001, p_new_len);
if (use_fps && animation->get_step() > 0) { if (use_fps && animation->get_step() > 0) {
p_new_len *= animation->get_step(); p_new_len *= animation->get_step();
} }
@ -1539,7 +1365,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
float l = animation->get_length(); float l = animation->get_length();
if (l <= 0) { if (l <= 0) {
l = 0.001; // Avoid crashor. l = 0.0001; // Avoid crashor.
} }
Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons")); Ref<Texture2D> hsize_icon = get_theme_icon(SNAME("Hsize"), SNAME("EditorIcons"));
@ -1600,7 +1426,7 @@ void AnimationTimelineEdit::_notification(int p_what) {
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, h)), timecolor);
} }
} }
@ -1759,7 +1585,7 @@ void AnimationTimelineEdit::update_values() {
} }
} else { } else {
length->set_value(animation->get_length()); length->set_value(animation->get_length());
length->set_step(0.001); length->set_step(0.0001);
length->set_tooltip_text(TTR("Animation length (seconds)")); length->set_tooltip_text(TTR("Animation length (seconds)"));
time_icon->set_tooltip_text(TTR("Animation length (seconds)")); time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
} }
@ -1950,9 +1776,9 @@ AnimationTimelineEdit::AnimationTimelineEdit() {
time_icon->set_tooltip_text(TTR("Animation length (seconds)")); time_icon->set_tooltip_text(TTR("Animation length (seconds)"));
len_hb->add_child(time_icon); len_hb->add_child(time_icon);
length = memnew(EditorSpinSlider); length = memnew(EditorSpinSlider);
length->set_min(0.001); length->set_min(0.0001);
length->set_max(36000); length->set_max(36000);
length->set_step(0.001); length->set_step(0.0001);
length->set_allow_greater(true); length->set_allow_greater(true);
length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0)); length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
length->set_hide_slider(true); length->set_hide_slider(true);
@ -2058,7 +1884,7 @@ void AnimationTrackEdit::_notification(int p_what) {
} else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) { } else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) {
text = TTR("Audio Clips:"); text = TTR("Audio Clips:");
} else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) { } else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) {
text = TTR("Anim Clips:"); text = TTR("Animation Clips:");
} else { } else {
text += anim_path.get_concatenated_subnames(); text += anim_path.get_concatenated_subnames();
} }
@ -2670,7 +2496,7 @@ String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
} }
if (key_idx != -1) { if (key_idx != -1) {
String text = TTR("Time (s):") + " " + rtos(animation->track_get_key_time(track, key_idx)) + "\n"; String text = TTR("Time (s):") + " " + TS->format_number(rtos(Math::snapped(animation->track_get_key_time(track, key_idx), 0.0001))) + "\n";
switch (animation->track_get_type(track)) { switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D: { case Animation::TYPE_POSITION_3D: {
Vector3 t = animation->track_get_key_value(track, key_idx); Vector3 t = animation->track_get_key_value(track, key_idx);
@ -4390,7 +4216,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
p_next_tracks.normal++; p_next_tracks.normal++;
} else { } else {
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_id.track_idx, time); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", p_id.track_idx, time);
int existing = animation->track_find_key(p_id.track_idx, time, true); int existing = animation->track_find_key(p_id.track_idx, time, Animation::FIND_MODE_APPROX);
if (existing != -1) { if (existing != -1) {
Variant v = animation->track_get_key_value(p_id.track_idx, existing); Variant v = animation->track_get_key_value(p_id.track_idx, existing);
float trans = animation->track_get_key_transition(p_id.track_idx, existing); float trans = animation->track_get_key_transition(p_id.track_idx, existing);
@ -5005,8 +4831,8 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
if (snap->is_pressed() && step->get_value() != 0) { if (snap->is_pressed() && step->get_value() != 0) {
p_ofs = snap_time(p_ofs); p_ofs = snap_time(p_ofs);
} }
while (animation->track_find_key(p_track, p_ofs, true) != -1) { // Make sure insertion point is valid. while (animation->track_find_key(p_track, p_ofs, Animation::FIND_MODE_APPROX) != -1) { // Make sure insertion point is valid.
p_ofs += 0.001; p_ofs += 0.0001;
} }
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
@ -5338,7 +5164,7 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t
return; return;
} }
int idx = animation->track_find_key(p_track, p_pos, true); int idx = animation->track_find_key(p_track, p_pos, Animation::FIND_MODE_APPROX);
ERR_FAIL_COND(idx < 0); ERR_FAIL_COND(idx < 0);
SelectedKey sk; SelectedKey sk;
@ -5365,7 +5191,7 @@ void AnimationTrackEditor::_move_selection_commit() {
// 2 - Remove overlapped keys. // 2 - Remove overlapped keys.
for (RBMap<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); float newtime = snap_time(E->get().pos + motion);
int idx = animation->track_find_key(E->key().track, newtime, true); int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) { if (idx == -1) {
continue; continue;
} }
@ -5625,7 +5451,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
continue; continue;
} }
int existing_idx = animation->track_find_key(dst_track, dst_time, true); int existing_idx = animation->track_find_key(dst_track, dst_time, Animation::FIND_MODE_APPROX);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key)); undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", dst_track, dst_time); undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", dst_track, dst_time);
@ -5916,7 +5742,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
// 2 - Remove overlapped keys. // 2 - Remove overlapped keys.
for (RBMap<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; float newtime = (E->get().pos - from_t) * s + from_t;
int idx = animation->track_find_key(E->key().track, newtime, true); int idx = animation->track_find_key(E->key().track, newtime, Animation::FIND_MODE_APPROX);
if (idx == -1) { if (idx == -1) {
continue; continue;
} }
@ -6127,7 +5953,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
undo_redo->add_do_method(reset.ptr(), "track_set_path", dst_track, path); undo_redo->add_do_method(reset.ptr(), "track_set_path", dst_track, path);
undo_redo->add_undo_method(reset.ptr(), "remove_track", dst_track); undo_redo->add_undo_method(reset.ptr(), "remove_track", dst_track);
} else { } else {
existing_idx = reset->track_find_key(dst_track, 0, true); existing_idx = reset->track_find_key(dst_track, 0, Animation::FIND_MODE_APPROX);
} }
undo_redo->add_do_method(reset.ptr(), "track_insert_key", dst_track, 0, animation->track_get_key_value(sk.track, sk.key), animation->track_get_key_transition(sk.track, sk.key)); undo_redo->add_do_method(reset.ptr(), "track_insert_key", dst_track, 0, animation->track_get_key_value(sk.track, sk.key), animation->track_get_key_transition(sk.track, sk.key));
@ -6656,7 +6482,7 @@ AnimationTrackEditor::AnimationTrackEditor() {
step = memnew(EditorSpinSlider); step = memnew(EditorSpinSlider);
step->set_min(0); step->set_min(0);
step->set_max(1000000); step->set_max(1000000);
step->set_step(0.001); step->set_step(0.0001);
step->set_hide_slider(true); step->set_hide_slider(true);
step->set_custom_minimum_size(Size2(100, 0) * EDSCALE); step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
step->set_tooltip_text(TTR("Animation step value.")); step->set_tooltip_text(TTR("Animation step value."));
@ -6946,3 +6772,103 @@ AnimationTrackEditor::~AnimationTrackEditor() {
memdelete(multi_key_edit); memdelete(multi_key_edit);
} }
} }
// AnimationTrackKeyEditEditorPlugin
void AnimationTrackKeyEditEditor::_time_edit_entered() {
int key = animation->track_find_key(track, key_ofs, Animation::FIND_MODE_APPROX);
if (key == -1) {
return;
}
key_data_cache.time = animation->track_get_key_time(track, key);
key_data_cache.transition = animation->track_get_key_transition(track, key);
key_data_cache.value = animation->track_get_key_value(track, key);
}
void AnimationTrackKeyEditEditor::_time_edit_exited() {
real_t new_time = spinner->get_value();
if (use_fps) {
real_t fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
new_time /= fps;
}
if (Math::is_equal_approx(new_time, key_data_cache.time)) {
return; // No change.
}
int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX);
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
if (existing != -1) {
undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, animation->track_get_key_time(track, existing));
}
undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", track, key_data_cache.time);
undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, key_data_cache.value, key_data_cache.transition);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", track, new_time);
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_data_cache.time, key_data_cache.value, key_data_cache.transition);
if (existing != -1) {
undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, animation->track_get_key_time(track, existing), animation->track_get_key_value(track, existing), animation->track_get_key_transition(track, existing));
}
// Reselect key.
AnimationPlayerEditor *ape = AnimationPlayerEditor::get_singleton();
if (ape) {
AnimationTrackEditor *ate = ape->get_track_editor();
if (ate) {
undo_redo->add_do_method(ate, "_clear_selection_for_anim", animation);
undo_redo->add_undo_method(ate, "_clear_selection_for_anim", animation);
undo_redo->add_do_method(ate, "_select_at_anim", animation, track, new_time);
undo_redo->add_undo_method(ate, "_select_at_anim", animation, track, key_data_cache.time);
}
}
undo_redo->commit_action();
}
AnimationTrackKeyEditEditor::AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps) {
if (!p_animation.is_valid()) {
return;
}
animation = p_animation;
track = p_track;
key_ofs = p_key_ofs;
use_fps = p_use_fps;
set_label("Time");
spinner = memnew(EditorSpinSlider);
spinner->set_focus_mode(Control::FOCUS_CLICK);
spinner->set_min(0);
spinner->set_allow_greater(true);
spinner->set_allow_lesser(true);
if (use_fps) {
spinner->set_step(1);
spinner->set_hide_slider(true);
real_t fps = animation->get_step();
if (fps > 0) {
fps = 1.0 / fps;
}
spinner->set_value(key_ofs * fps);
} else {
spinner->set_step(0.0001);
spinner->set_value(key_ofs);
spinner->set_max(animation->get_length());
}
add_child(spinner);
spinner->connect("grabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("ungrabbed", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
spinner->connect("value_focus_entered", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_entered), CONNECT_DEFERRED);
spinner->connect("value_focus_exited", callable_mp(this, &AnimationTrackKeyEditEditor::_time_edit_exited), CONNECT_DEFERRED);
}
AnimationTrackKeyEditEditor::~AnimationTrackKeyEditEditor() {
}

View File

@ -50,9 +50,83 @@
#include "scene/resources/animation.h" #include "scene/resources/animation.h"
#include "scene_tree_editor.h" #include "scene_tree_editor.h"
class AnimationTrackEditor;
class AnimationTrackEdit; class AnimationTrackEdit;
class ViewPanner; class ViewPanner;
class AnimationTrackKeyEdit : public Object {
GDCLASS(AnimationTrackKeyEdit, Object);
public:
bool setting = false;
bool animation_read_only = false;
Ref<Animation> animation;
int track = -1;
float key_ofs = 0;
Node *root_path = nullptr;
PropertyInfo hint;
NodePath base;
bool use_fps = false;
bool _hide_script_from_inspector() { return true; }
bool _hide_metadata_from_inspector() { return true; }
bool _dont_undo_redo() { return true; }
bool _is_read_only() { return animation_read_only; }
void notify_change();
Node *get_root_path();
void set_use_fps(bool p_enable);
protected:
static void _bind_methods();
void _fix_node_path(Variant &value);
void _update_obj(const Ref<Animation> &p_anim);
void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
};
class AnimationMultiTrackKeyEdit : public Object {
GDCLASS(AnimationMultiTrackKeyEdit, Object);
public:
bool setting = false;
bool animation_read_only = false;
Ref<Animation> animation;
RBMap<int, List<float>> key_ofs_map;
RBMap<int, NodePath> base_map;
PropertyInfo hint;
Node *root_path = nullptr;
bool use_fps = false;
bool _hide_script_from_inspector() { return true; }
bool _hide_metadata_from_inspector() { return true; }
bool _dont_undo_redo() { return true; }
bool _is_read_only() { return animation_read_only; }
void notify_change();
Node *get_root_path();
void set_use_fps(bool p_enable);
protected:
static void _bind_methods();
void _fix_node_path(Variant &value, NodePath &base);
void _update_obj(const Ref<Animation> &p_anim);
void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
};
class AnimationTimelineEdit : public Range { class AnimationTimelineEdit : public Range {
GDCLASS(AnimationTimelineEdit, Range); GDCLASS(AnimationTimelineEdit, Range);
@ -129,8 +203,6 @@ public:
AnimationTimelineEdit(); AnimationTimelineEdit();
}; };
class AnimationTrackEditor;
class AnimationTrackEdit : public Control { class AnimationTrackEdit : public Control {
GDCLASS(AnimationTrackEdit, Control); GDCLASS(AnimationTrackEdit, Control);
friend class AnimationTimelineEdit; friend class AnimationTimelineEdit;
@ -592,4 +664,30 @@ public:
~AnimationTrackEditor(); ~AnimationTrackEditor();
}; };
// AnimationTrackKeyEditEditorPlugin
class AnimationTrackKeyEditEditor : public EditorProperty {
GDCLASS(AnimationTrackKeyEditEditor, EditorProperty);
Ref<Animation> animation;
int track = -1;
real_t key_ofs = 0.0;
bool use_fps = false;
EditorSpinSlider *spinner = nullptr;
struct KeyDataCache {
real_t time = 0.0;
float transition = 0.0;
Variant value;
} key_data_cache;
void _time_edit_entered();
void _time_edit_exited();
public:
AnimationTrackKeyEditEditor(Ref<Animation> p_animation, int p_track, real_t p_key_ofs, bool p_use_fps);
~AnimationTrackKeyEditEditor();
};
#endif // ANIMATION_TRACK_EDITOR_H #endif // ANIMATION_TRACK_EDITOR_H

View File

@ -831,8 +831,8 @@ Rect2 AnimationTrackEditTypeAudio::get_key_rect(int p_index, float p_pixels_sec)
len -= end_ofs; len -= end_ofs;
len -= start_ofs; len -= start_ofs;
if (len <= 0.001) { if (len <= 0.0001) {
len = 0.001; len = 0.0001;
} }
if (get_animation()->track_get_key_count(get_track()) > p_index + 1) { if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {
@ -887,8 +887,8 @@ void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int
len -= end_ofs; len -= end_ofs;
len -= start_ofs; len -= start_ofs;
if (len <= 0.001) { if (len <= 0.0001) {
len = 0.001; len = 0.0001;
} }
int pixel_len = len * p_pixels_sec; int pixel_len = len * p_pixels_sec;
@ -1014,8 +1014,8 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
ofs = get_editor()->snap_time(ofs); ofs = get_editor()->snap_time(ofs);
while (get_animation()->track_find_key(get_track(), ofs, true) != -1) { //make sure insertion point is valid while (get_animation()->track_find_key(get_track(), ofs, Animation::FIND_MODE_APPROX) != -1) { //make sure insertion point is valid
ofs += 0.001; ofs += 0.0001;
} }
Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo(); Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();

View File

@ -7262,6 +7262,7 @@ EditorNode::EditorNode() {
gui_base->add_child(disk_changed); gui_base->add_child(disk_changed);
add_editor_plugin(memnew(AnimationPlayerEditorPlugin)); add_editor_plugin(memnew(AnimationPlayerEditorPlugin));
add_editor_plugin(memnew(AnimationTrackKeyEditEditorPlugin));
add_editor_plugin(memnew(CanvasItemEditorPlugin)); add_editor_plugin(memnew(CanvasItemEditorPlugin));
add_editor_plugin(memnew(Node3DEditorPlugin)); add_editor_plugin(memnew(Node3DEditorPlugin));
add_editor_plugin(memnew(ScriptEditorPlugin)); add_editor_plugin(memnew(ScriptEditorPlugin));

View File

@ -1384,10 +1384,11 @@ void EditorPropertyInteger::update_property() {
void EditorPropertyInteger::_bind_methods() { void EditorPropertyInteger::_bind_methods() {
} }
void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) { void EditorPropertyInteger::setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_hide_slider, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix) {
spin->set_min(p_min); spin->set_min(p_min);
spin->set_max(p_max); spin->set_max(p_max);
spin->set_step(p_step); spin->set_step(p_step);
spin->set_hide_slider(p_hide_slider);
spin->set_allow_greater(p_allow_greater); spin->set_allow_greater(p_allow_greater);
spin->set_allow_lesser(p_allow_lesser); spin->set_allow_lesser(p_allow_lesser);
spin->set_suffix(p_suffix); spin->set_suffix(p_suffix);
@ -2242,12 +2243,11 @@ void EditorPropertyVector2i::_notification(int p_what) {
} }
} }
void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) { void EditorPropertyVector2i::setup(int p_min, int p_max, bool p_link, const String &p_suffix) {
for (int i = 0; i < 2; i++) { for (int i = 0; i < 2; i++) {
spin[i]->set_min(p_min); spin[i]->set_min(p_min);
spin[i]->set_max(p_max); spin[i]->set_max(p_max);
spin[i]->set_step(1); spin[i]->set_step(1);
spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true); spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true); spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix); spin[i]->set_suffix(p_suffix);
@ -2352,12 +2352,11 @@ void EditorPropertyRect2i::_notification(int p_what) {
void EditorPropertyRect2i::_bind_methods() { void EditorPropertyRect2i::_bind_methods() {
} }
void EditorPropertyRect2i::setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix) { void EditorPropertyRect2i::setup(int p_min, int p_max, const String &p_suffix) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min); spin[i]->set_min(p_min);
spin[i]->set_max(p_max); spin[i]->set_max(p_max);
spin[i]->set_step(1); spin[i]->set_step(1);
spin[i]->set_hide_slider(p_hide_slider);
spin[i]->set_allow_greater(true); spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true); spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix); spin[i]->set_suffix(p_suffix);
@ -2496,12 +2495,12 @@ void EditorPropertyVector3i::_notification(int p_what) {
void EditorPropertyVector3i::_bind_methods() { void EditorPropertyVector3i::_bind_methods() {
} }
void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_hide_slider, bool p_link, const String &p_suffix) { void EditorPropertyVector3i::setup(int p_min, int p_max, bool p_link, const String &p_suffix) {
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
spin[i]->set_min(p_min); spin[i]->set_min(p_min);
spin[i]->set_max(p_max); spin[i]->set_max(p_max);
spin[i]->set_step(1); spin[i]->set_step(1);
spin[i]->set_hide_slider(p_hide_slider); spin[i]->set_hide_slider(false);
spin[i]->set_allow_greater(true); spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true); spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix); spin[i]->set_suffix(p_suffix);
@ -3004,11 +3003,11 @@ void EditorPropertyVector4i::_notification(int p_what) {
void EditorPropertyVector4i::_bind_methods() { void EditorPropertyVector4i::_bind_methods() {
} }
void EditorPropertyVector4i::setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix) { void EditorPropertyVector4i::setup(double p_min, double p_max, const String &p_suffix) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
spin[i]->set_min(p_min); spin[i]->set_min(p_min);
spin[i]->set_max(p_max); spin[i]->set_max(p_max);
spin[i]->set_hide_slider(p_hide_slider); spin[i]->set_step(1);
spin[i]->set_allow_greater(true); spin[i]->set_allow_greater(true);
spin[i]->set_allow_lesser(true); spin[i]->set_allow_lesser(true);
spin[i]->set_suffix(p_suffix); spin[i]->set_suffix(p_suffix);
@ -4347,7 +4346,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
EditorPropertyInteger *editor = memnew(EditorPropertyInteger); EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
editor->setup(hint.min, hint.max, hint.step, hint.or_greater, hint.or_less, hint.suffix); editor->setup(hint.min, hint.max, hint.step, hint.hide_slider, hint.or_greater, hint.or_less, hint.suffix);
return editor; return editor;
} }
@ -4475,7 +4474,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR2I: { case Variant::VECTOR2I: {
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide)); EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix); editor->setup(hint.min, hint.max, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor; return editor;
} break; } break;
@ -4488,7 +4487,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::RECT2I: { case Variant::RECT2I: {
EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i(p_wide)); EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); editor->setup(hint.min, hint.max, hint.suffix);
return editor; return editor;
} break; } break;
@ -4502,7 +4501,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR3I: { case Variant::VECTOR3I: {
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide)); EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i(p_wide));
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
editor->setup(hint.min, hint.max, hint.hide_slider, p_hint == PROPERTY_HINT_LINK, hint.suffix); editor->setup(hint.min, hint.max, p_hint == PROPERTY_HINT_LINK, hint.suffix);
return editor; return editor;
} break; } break;
@ -4516,7 +4515,7 @@ EditorProperty *EditorInspectorDefaultPlugin::get_editor_for_property(Object *p_
case Variant::VECTOR4I: { case Variant::VECTOR4I: {
EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i); EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1); EditorPropertyRangeHint hint = _parse_range_hint(p_hint, p_hint_text, 1);
editor->setup(hint.min, hint.max, hint.hide_slider, hint.suffix); editor->setup(hint.min, hint.max, hint.suffix);
return editor; return editor;
} break; } break;

View File

@ -378,7 +378,7 @@ protected:
public: public:
virtual void update_property() override; virtual void update_property() override;
void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String()); void setup(int64_t p_min, int64_t p_max, int64_t p_step, bool p_hide_slider, bool p_allow_greater, bool p_allow_lesser, const String &p_suffix = String());
EditorPropertyInteger(); EditorPropertyInteger();
}; };
@ -566,7 +566,7 @@ protected:
public: public:
virtual void update_property() override; virtual void update_property() override;
void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String()); void setup(int p_min, int p_max, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector2i(bool p_force_wide = false); EditorPropertyVector2i(bool p_force_wide = false);
}; };
@ -583,7 +583,7 @@ protected:
public: public:
virtual void update_property() override; virtual void update_property() override;
void setup(int p_min, int p_max, bool p_hide_slider, const String &p_suffix = String()); void setup(int p_min, int p_max, const String &p_suffix = String());
EditorPropertyRect2i(bool p_force_wide = false); EditorPropertyRect2i(bool p_force_wide = false);
}; };
@ -608,7 +608,7 @@ protected:
public: public:
virtual void update_property() override; virtual void update_property() override;
void setup(int p_min, int p_max, bool p_hide_slider, bool p_link = false, const String &p_suffix = String()); void setup(int p_min, int p_max, bool p_link = false, const String &p_suffix = String());
EditorPropertyVector3i(bool p_force_wide = false); EditorPropertyVector3i(bool p_force_wide = false);
}; };
@ -693,7 +693,7 @@ protected:
public: public:
virtual void update_property() override; virtual void update_property() override;
void setup(double p_min, double p_max, bool p_hide_slider, const String &p_suffix = String()); void setup(double p_min, double p_max, const String &p_suffix = String());
EditorPropertyVector4i(); EditorPropertyVector4i();
}; };

View File

@ -919,7 +919,7 @@ void EditorPropertyDictionary::update_property() {
} break; } break;
case Variant::INT: { case Variant::INT: {
EditorPropertyInteger *editor = memnew(EditorPropertyInteger); EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
editor->setup(-100000, 100000, 1, true, true); editor->setup(-100000, 100000, 1, false, true, true);
prop = editor; prop = editor;
} break; } break;
@ -942,7 +942,7 @@ void EditorPropertyDictionary::update_property() {
} break; } break;
case Variant::VECTOR2I: { case Variant::VECTOR2I: {
EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i); EditorPropertyVector2i *editor = memnew(EditorPropertyVector2i);
editor->setup(-100000, 100000, true); editor->setup(-100000, 100000);
prop = editor; prop = editor;
} break; } break;
@ -954,7 +954,7 @@ void EditorPropertyDictionary::update_property() {
} break; } break;
case Variant::RECT2I: { case Variant::RECT2I: {
EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i); EditorPropertyRect2i *editor = memnew(EditorPropertyRect2i);
editor->setup(-100000, 100000, true); editor->setup(-100000, 100000);
prop = editor; prop = editor;
} break; } break;
@ -966,7 +966,7 @@ void EditorPropertyDictionary::update_property() {
} break; } break;
case Variant::VECTOR3I: { case Variant::VECTOR3I: {
EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i); EditorPropertyVector3i *editor = memnew(EditorPropertyVector3i);
editor->setup(-100000, 100000, true); editor->setup(-100000, 100000);
prop = editor; prop = editor;
} break; } break;
@ -978,7 +978,7 @@ void EditorPropertyDictionary::update_property() {
} break; } break;
case Variant::VECTOR4I: { case Variant::VECTOR4I: {
EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i); EditorPropertyVector4i *editor = memnew(EditorPropertyVector4i);
editor->setup(-100000, 100000, true); editor->setup(-100000, 100000);
prop = editor; prop = editor;
} break; } break;

View File

@ -76,6 +76,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
pre_grab_value = get_value(); pre_grab_value = get_value();
grabbing_spinner = false; grabbing_spinner = false;
grabbing_spinner_mouse_pos = get_global_mouse_position(); grabbing_spinner_mouse_pos = get_global_mouse_position();
emit_signal("grabbed");
} }
} else { } else {
if (grabbing_spinner_attempt) { if (grabbing_spinner_attempt) {
@ -83,6 +84,7 @@ void EditorSpinSlider::gui_input(const Ref<InputEvent> &p_event) {
Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE);
Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos); Input::get_singleton()->warp_mouse(grabbing_spinner_mouse_pos);
queue_redraw(); queue_redraw();
emit_signal("ungrabbed");
} else { } else {
_focus_entered(); _focus_entered();
} }
@ -178,9 +180,11 @@ void EditorSpinSlider::_grabber_gui_input(const Ref<InputEvent> &p_event) {
grabbing_ratio = get_as_ratio(); grabbing_ratio = get_as_ratio();
grabbing_from = grabber->get_transform().xform(mb->get_position()).x; grabbing_from = grabber->get_transform().xform(mb->get_position()).x;
} }
emit_signal("grabbed");
} else { } else {
grabbing_grabber = false; grabbing_grabber = false;
mousewheel_over_grabber = false; mousewheel_over_grabber = false;
emit_signal("ungrabbed");
} }
} }
@ -299,10 +303,6 @@ void EditorSpinSlider::_draw_spin_slider() {
Ref<Texture2D> updown = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox")); Ref<Texture2D> updown = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
if (get_step() == 1) {
number_width -= updown->get_width();
}
String numstr = get_text_value(); String numstr = get_text_value();
int vofs = (size.height - font->get_height(font_size)) / 2 + font->get_ascent(font_size); int vofs = (size.height - font->get_height(font_size)) / 2 + font->get_ascent(font_size);
@ -359,7 +359,9 @@ void EditorSpinSlider::_draw_spin_slider() {
} }
TS->free_rid(num_rid); TS->free_rid(num_rid);
if (!hide_slider) {
if (get_step() == 1) { if (get_step() == 1) {
number_width -= updown->get_width();
Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox")); Ref<Texture2D> updown2 = get_theme_icon(is_read_only() ? SNAME("updown_disabled") : SNAME("updown"), SNAME("SpinBox"));
int updown_vofs = (size.height - updown2->get_height()) / 2; int updown_vofs = (size.height - updown2->get_height()) / 2;
if (rtl) { if (rtl) {
@ -375,7 +377,7 @@ void EditorSpinSlider::_draw_spin_slider() {
if (grabber->is_visible()) { if (grabber->is_visible()) {
grabber->hide(); grabber->hide();
} }
} else if (!hide_slider) { } else {
const int grabber_w = 4 * EDSCALE; const int grabber_w = 4 * EDSCALE;
const int width = size.width - sb->get_minimum_size().width - grabber_w; const int width = size.width - sb->get_minimum_size().width - grabber_w;
const int ofs = sb->get_offset().x; const int ofs = sb->get_offset().x;
@ -431,6 +433,7 @@ void EditorSpinSlider::_draw_spin_slider() {
grabber_range = width; grabber_range = width;
} }
} }
}
} }
void EditorSpinSlider::_notification(int p_what) { void EditorSpinSlider::_notification(int p_what) {
@ -584,6 +587,8 @@ void EditorSpinSlider::_value_focus_exited() {
//enter, click, esc //enter, click, esc
grab_focus(); grab_focus();
} }
emit_signal("value_focus_exited");
} }
void EditorSpinSlider::_grabber_mouse_entered() { void EditorSpinSlider::_grabber_mouse_entered() {
@ -627,6 +632,7 @@ void EditorSpinSlider::_focus_entered() {
value_input->call_deferred(SNAME("select_all")); value_input->call_deferred(SNAME("select_all"));
value_input->set_focus_next(find_next_valid_focus()->get_path()); value_input->set_focus_next(find_next_valid_focus()->get_path());
value_input->set_focus_previous(find_prev_valid_focus()->get_path()); value_input->set_focus_previous(find_prev_valid_focus()->get_path());
emit_signal("value_focus_entered");
} }
void EditorSpinSlider::_bind_methods() { void EditorSpinSlider::_bind_methods() {
@ -650,6 +656,11 @@ void EditorSpinSlider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_slider"), "set_hide_slider", "is_hiding_slider"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hide_slider"), "set_hide_slider", "is_hiding_slider");
ADD_SIGNAL(MethodInfo("grabbed"));
ADD_SIGNAL(MethodInfo("ungrabbed"));
ADD_SIGNAL(MethodInfo("value_focus_entered"));
ADD_SIGNAL(MethodInfo("value_focus_exited"));
} }
void EditorSpinSlider::_ensure_input_popup() { void EditorSpinSlider::_ensure_input_popup() {

View File

@ -87,13 +87,13 @@ void AnimationPlayerEditor::_notification(int p_what) {
} }
frame->set_value(player->get_current_animation_position()); frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position()); track_editor->set_anim_pos(player->get_current_animation_position());
} else if (!player->is_valid()) { } else if (!player->is_valid()) {
// Reset timeline when the player has been stopped externally // Reset timeline when the player has been stopped externally
frame->set_value(0); frame->set_value(0);
} else if (last_active) { } else if (last_active) {
// Need the last frame after it stopped. // Need the last frame after it stopped.
frame->set_value(player->get_current_animation_position()); frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position());
} }
last_active = player->is_playing(); last_active = player->is_playing();
@ -423,7 +423,7 @@ void AnimationPlayerEditor::_select_anim_by_name(const String &p_anim) {
_animation_selected(idx); _animation_selected(idx);
} }
double AnimationPlayerEditor::_get_editor_step() const { float AnimationPlayerEditor::_get_editor_step() const {
// Returns the effective snapping value depending on snapping modifiers, or 0 if snapping is disabled. // Returns the effective snapping value depending on snapping modifiers, or 0 if snapping is disabled.
if (track_editor->is_snap_enabled()) { if (track_editor->is_snap_enabled()) {
const String current = player->get_assigned_animation(); const String current = player->get_assigned_animation();
@ -434,7 +434,7 @@ double AnimationPlayerEditor::_get_editor_step() const {
return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step(); return Input::get_singleton()->is_key_pressed(Key::SHIFT) ? anim->get_step() * 0.25 : anim->get_step();
} }
return 0.0; return 0.0f;
} }
void AnimationPlayerEditor::_animation_name_edited() { void AnimationPlayerEditor::_animation_name_edited() {
@ -1973,3 +1973,26 @@ AnimationPlayerEditorPlugin::AnimationPlayerEditorPlugin() {
AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() { AnimationPlayerEditorPlugin::~AnimationPlayerEditorPlugin() {
} }
// AnimationTrackKeyEditEditorPlugin
bool EditorInspectorPluginAnimationTrackKeyEdit::can_handle(Object *p_object) {
return Object::cast_to<AnimationTrackKeyEdit>(p_object) != nullptr;
}
void EditorInspectorPluginAnimationTrackKeyEdit::parse_begin(Object *p_object) {
AnimationTrackKeyEdit *atk = Object::cast_to<AnimationTrackKeyEdit>(p_object);
ERR_FAIL_COND(!atk);
atk_editor = memnew(AnimationTrackKeyEditEditor(atk->animation, atk->track, atk->key_ofs, atk->use_fps));
add_custom_control(atk_editor);
}
AnimationTrackKeyEditEditorPlugin::AnimationTrackKeyEditEditorPlugin() {
atk_plugin = memnew(EditorInspectorPluginAnimationTrackKeyEdit);
EditorInspector::add_inspector_plugin(atk_plugin);
}
bool AnimationTrackKeyEditEditorPlugin::handles(Object *p_object) const {
return p_object->is_class("AnimationTrackKeyEdit");
}

View File

@ -162,7 +162,7 @@ class AnimationPlayerEditor : public VBoxContainer {
} onion; } onion;
void _select_anim_by_name(const String &p_anim); void _select_anim_by_name(const String &p_anim);
double _get_editor_step() const; float _get_editor_step() const;
void _play_pressed(); void _play_pressed();
void _play_from_pressed(); void _play_from_pressed();
void _play_bw_pressed(); void _play_bw_pressed();
@ -272,4 +272,30 @@ public:
~AnimationPlayerEditorPlugin(); ~AnimationPlayerEditorPlugin();
}; };
// AnimationTrackKeyEditEditorPlugin
class EditorInspectorPluginAnimationTrackKeyEdit : public EditorInspectorPlugin {
GDCLASS(EditorInspectorPluginAnimationTrackKeyEdit, EditorInspectorPlugin);
AnimationTrackKeyEditEditor *atk_editor = nullptr;
public:
virtual bool can_handle(Object *p_object) override;
virtual void parse_begin(Object *p_object) override;
};
class AnimationTrackKeyEditEditorPlugin : public EditorPlugin {
GDCLASS(AnimationTrackKeyEditEditorPlugin, EditorPlugin);
EditorInspectorPluginAnimationTrackKeyEdit *atk_plugin = nullptr;
public:
bool has_main_screen() const override { return false; }
virtual bool handles(Object *p_object) const override;
virtual String get_name() const override { return "AnimationTrackKeyEdit"; }
AnimationTrackKeyEditEditorPlugin();
};
#endif // ANIMATION_PLAYER_EDITOR_PLUGIN_H #endif // ANIMATION_PLAYER_EDITOR_PLUGIN_H

View File

@ -483,7 +483,7 @@ void EditorPropertyOTVariation::update_property() {
Vector3i range = supported.get_value_at_index(i); Vector3i range = supported.get_value_at_index(i);
EditorPropertyInteger *prop = memnew(EditorPropertyInteger); EditorPropertyInteger *prop = memnew(EditorPropertyInteger);
prop->setup(range.x, range.y, 1, false, false); prop->setup(range.x, range.y, false, 1, false, false);
prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag)); prop->set_object_and_property(object.ptr(), "keys/" + itos(name_tag));
String name = TS->tag_to_name(name_tag); String name = TS->tag_to_name(name_tag);
@ -762,7 +762,7 @@ void EditorPropertyOTFeatures::update_property() {
} break; } break;
case Variant::INT: { case Variant::INT: {
EditorPropertyInteger *editor = memnew(EditorPropertyInteger); EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
editor->setup(0, 255, 1, false, false); editor->setup(0, 255, 1, false, false, false);
prop = editor; prop = editor;
} break; } break;
default: { default: {

View File

@ -398,7 +398,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
source_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); source_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
source_from_property_editor->set_selectable(false); source_from_property_editor->set_selectable(false);
source_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); source_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
source_from_property_editor->setup(-1, 99999, 1, true, false); source_from_property_editor->setup(-1, 99999, 1, false, true, false);
vboxcontainer_from->add_child(source_from_property_editor); vboxcontainer_from->add_child(source_from_property_editor);
coords_from_property_editor = memnew(EditorPropertyVector2i); coords_from_property_editor = memnew(EditorPropertyVector2i);
@ -417,7 +417,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
alternative_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); alternative_from_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
alternative_from_property_editor->set_selectable(false); alternative_from_property_editor->set_selectable(false);
alternative_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); alternative_from_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
alternative_from_property_editor->setup(-1, 99999, 1, true, false); alternative_from_property_editor->setup(-1, 99999, 1, false, true, false);
alternative_from_property_editor->hide(); alternative_from_property_editor->hide();
vboxcontainer_from->add_child(alternative_from_property_editor); vboxcontainer_from->add_child(alternative_from_property_editor);
@ -432,7 +432,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
source_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); source_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
source_to_property_editor->set_selectable(false); source_to_property_editor->set_selectable(false);
source_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); source_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
source_to_property_editor->setup(-1, 99999, 1, true, false); source_to_property_editor->setup(-1, 99999, 1, false, true, false);
vboxcontainer_to->add_child(source_to_property_editor); vboxcontainer_to->add_child(source_to_property_editor);
coords_to_property_editor = memnew(EditorPropertyVector2i); coords_to_property_editor = memnew(EditorPropertyVector2i);
@ -451,7 +451,7 @@ TileProxiesManagerDialog::TileProxiesManagerDialog() {
alternative_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed)); alternative_to_property_editor->connect("property_changed", callable_mp(this, &TileProxiesManagerDialog::_property_changed));
alternative_to_property_editor->set_selectable(false); alternative_to_property_editor->set_selectable(false);
alternative_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL); alternative_to_property_editor->set_h_size_flags(Control::SIZE_EXPAND_FILL);
alternative_to_property_editor->setup(-1, 99999, 1, true, false); alternative_to_property_editor->setup(-1, 99999, 1, false, true, false);
alternative_to_property_editor->hide(); alternative_to_property_editor->hide();
vboxcontainer_to->add_child(alternative_to_property_editor); vboxcontainer_to->add_child(alternative_to_property_editor);

View File

@ -691,7 +691,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} }
} else { } else {
if (p_started) { if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true); int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) { if (first_key >= 0) {
indices.push_back(first_key); indices.push_back(first_key);
} }
@ -761,7 +761,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
} }
} else { } else {
if (p_started) { if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true); int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) { if (first_key >= 0) {
indices.push_back(first_key); indices.push_back(first_key);
} }
@ -855,7 +855,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
//find stuff to play //find stuff to play
List<int> to_play; List<int> to_play;
if (p_started) { if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true); int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) { if (first_key >= 0) {
to_play.push_back(first_key); to_play.push_back(first_key);
} }
@ -968,7 +968,7 @@ void AnimationPlayer::_animation_process_animation(AnimationData *p_anim, double
//find stuff to play //find stuff to play
List<int> to_play; List<int> to_play;
if (p_started) { if (p_started) {
int first_key = a->track_find_key(i, p_prev_time, true); int first_key = a->track_find_key(i, p_prev_time, Animation::FIND_MODE_EXACT);
if (first_key >= 0) { if (first_key >= 0) {
to_play.push_back(first_key); to_play.push_back(first_key);
} }

View File

@ -1383,7 +1383,7 @@ void AnimationTree::_process_graph(double p_delta) {
} }
} else { } else {
if (seeked) { if (seeked) {
int idx = a->track_find_key(i, time, !is_external_seeking); int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) { if (idx < 0) {
continue; continue;
} }
@ -1406,7 +1406,7 @@ void AnimationTree::_process_graph(double p_delta) {
TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track); TrackCacheMethod *t = static_cast<TrackCacheMethod *>(track);
if (seeked) { if (seeked) {
int idx = a->track_find_key(i, time, !is_external_seeking); int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) { if (idx < 0) {
continue; continue;
} }
@ -1440,7 +1440,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (seeked) { if (seeked) {
//find whatever should be playing //find whatever should be playing
int idx = a->track_find_key(i, time, !is_external_seeking); int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) { if (idx < 0) {
continue; continue;
} }
@ -1553,7 +1553,7 @@ void AnimationTree::_process_graph(double p_delta) {
if (seeked) { if (seeked) {
//seek //seek
int idx = a->track_find_key(i, time, !is_external_seeking); int idx = a->track_find_key(i, time, is_external_seeking ? Animation::FIND_MODE_NEAREST : Animation::FIND_MODE_EXACT);
if (idx < 0) { if (idx < 0) {
continue; continue;
} }

View File

@ -1319,7 +1319,7 @@ Error Animation::blend_shape_track_interpolate(int p_track, double p_time, float
} }
void Animation::track_remove_key_at_time(int p_track, double p_time) { void Animation::track_remove_key_at_time(int p_track, double p_time) {
int idx = track_find_key(p_track, p_time, true); int idx = track_find_key(p_track, p_time, FIND_MODE_APPROX);
ERR_FAIL_COND(idx < 0); ERR_FAIL_COND(idx < 0);
track_remove_key(p_track, idx); track_remove_key(p_track, idx);
} }
@ -1400,7 +1400,7 @@ void Animation::track_remove_key(int p_track, int p_idx) {
emit_changed(); emit_changed();
} }
int Animation::track_find_key(int p_track, double p_time, bool p_exact) const { int Animation::track_find_key(int p_track, double p_time, FindMode p_find_mode) const {
ERR_FAIL_INDEX_V(p_track, tracks.size(), -1); ERR_FAIL_INDEX_V(p_track, tracks.size(), -1);
Track *t = tracks[p_track]; Track *t = tracks[p_track];
@ -1416,7 +1416,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index; uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<3>(tt->compressed_track, p_time, key, time, key_next, time_next, &key_index); bool fetch_compressed_success = _fetch_compressed<3>(tt->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1); ERR_FAIL_COND_V(!fetch_compressed_success, -1);
if (p_exact && time != p_time) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1; return -1;
} }
return key_index; return key_index;
@ -1426,7 +1426,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= tt->positions.size()) { if (k < 0 || k >= tt->positions.size()) {
return -1; return -1;
} }
if (tt->positions[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(tt->positions[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && tt->positions[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1443,7 +1443,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index; uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<3>(rt->compressed_track, p_time, key, time, key_next, time_next, &key_index); bool fetch_compressed_success = _fetch_compressed<3>(rt->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1); ERR_FAIL_COND_V(!fetch_compressed_success, -1);
if (p_exact && time != p_time) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1; return -1;
} }
return key_index; return key_index;
@ -1453,7 +1453,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= rt->rotations.size()) { if (k < 0 || k >= rt->rotations.size()) {
return -1; return -1;
} }
if (rt->rotations[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(rt->rotations[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && rt->rotations[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1470,7 +1470,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index; uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<3>(st->compressed_track, p_time, key, time, key_next, time_next, &key_index); bool fetch_compressed_success = _fetch_compressed<3>(st->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1); ERR_FAIL_COND_V(!fetch_compressed_success, -1);
if (p_exact && time != p_time) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1; return -1;
} }
return key_index; return key_index;
@ -1480,7 +1480,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= st->scales.size()) { if (k < 0 || k >= st->scales.size()) {
return -1; return -1;
} }
if (st->scales[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(st->scales[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && st->scales[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1497,7 +1497,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
uint32_t key_index; uint32_t key_index;
bool fetch_compressed_success = _fetch_compressed<1>(bst->compressed_track, p_time, key, time, key_next, time_next, &key_index); bool fetch_compressed_success = _fetch_compressed<1>(bst->compressed_track, p_time, key, time, key_next, time_next, &key_index);
ERR_FAIL_COND_V(!fetch_compressed_success, -1); ERR_FAIL_COND_V(!fetch_compressed_success, -1);
if (p_exact && time != p_time) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(time, p_time)) || (p_find_mode == FIND_MODE_EXACT && time != p_time)) {
return -1; return -1;
} }
return key_index; return key_index;
@ -1507,7 +1507,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= bst->blend_shapes.size()) { if (k < 0 || k >= bst->blend_shapes.size()) {
return -1; return -1;
} }
if (bst->blend_shapes[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(bst->blend_shapes[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && bst->blend_shapes[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1519,7 +1519,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= vt->values.size()) { if (k < 0 || k >= vt->values.size()) {
return -1; return -1;
} }
if (vt->values[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(vt->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && vt->values[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1531,7 +1531,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= mt->methods.size()) { if (k < 0 || k >= mt->methods.size()) {
return -1; return -1;
} }
if (mt->methods[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(mt->methods[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && mt->methods[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1543,7 +1543,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= bt->values.size()) { if (k < 0 || k >= bt->values.size()) {
return -1; return -1;
} }
if (bt->values[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(bt->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && bt->values[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1555,7 +1555,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= at->values.size()) { if (k < 0 || k >= at->values.size()) {
return -1; return -1;
} }
if (at->values[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(at->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && at->values[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -1567,7 +1567,7 @@ int Animation::track_find_key(int p_track, double p_time, bool p_exact) const {
if (k < 0 || k >= at->values.size()) { if (k < 0 || k >= at->values.size()) {
return -1; return -1;
} }
if (at->values[k].time != p_time && p_exact) { if ((p_find_mode == FIND_MODE_APPROX && !Math::is_equal_approx(at->values[k].time, p_time)) || (p_find_mode == FIND_MODE_EXACT && at->values[k].time != p_time)) {
return -1; return -1;
} }
return k; return k;
@ -2944,12 +2944,12 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
// Not from_time > to_time but most recent of looping... // Not from_time > to_time but most recent of looping...
if (p_looped_flag != Animation::LOOPED_FLAG_NONE) { if (p_looped_flag != Animation::LOOPED_FLAG_NONE) {
if (!is_backward && Math::is_equal_approx(from_time, 0)) { if (!is_backward && Math::is_equal_approx(from_time, 0)) {
int edge = track_find_key(p_track, 0, true); int edge = track_find_key(p_track, 0, FIND_MODE_EXACT);
if (edge >= 0) { if (edge >= 0) {
p_indices->push_back(edge); p_indices->push_back(edge);
} }
} else if (is_backward && Math::is_equal_approx(to_time, length)) { } else if (is_backward && Math::is_equal_approx(to_time, length)) {
int edge = track_find_key(p_track, length, true); int edge = track_find_key(p_track, length, FIND_MODE_EXACT);
if (edge >= 0) { if (edge >= 0) {
p_indices->push_back(edge); p_indices->push_back(edge);
} }
@ -2971,7 +2971,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
const PositionTrack *tt = static_cast<const PositionTrack *>(t); const PositionTrack *tt = static_cast<const PositionTrack *>(t);
if (tt->compressed_track >= 0) { if (tt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices); _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(tt->compressed_track, CMP_EPSILON, to_time, p_indices); _get_compressed_key_indices_in_range<3>(tt->compressed_track, 0, to_time, p_indices);
} else { } else {
_track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices, true); _track_get_key_indices_in_range(tt->positions, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices, false); _track_get_key_indices_in_range(tt->positions, 0, to_time, p_indices, false);
@ -2981,7 +2981,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
const RotationTrack *rt = static_cast<const RotationTrack *>(t); const RotationTrack *rt = static_cast<const RotationTrack *>(t);
if (rt->compressed_track >= 0) { if (rt->compressed_track >= 0) {
_get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices); _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, from_time, p_indices);
_get_compressed_key_indices_in_range<3>(rt->compressed_track, CMP_EPSILON, to_time, p_indices); _get_compressed_key_indices_in_range<3>(rt->compressed_track, 0, to_time, p_indices);
} else { } else {
_track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices, true); _track_get_key_indices_in_range(rt->rotations, 0, from_time, p_indices, true);
_track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices, false); _track_get_key_indices_in_range(rt->rotations, 0, to_time, p_indices, false);
@ -3072,7 +3072,7 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t); const BlendShapeTrack *bst = static_cast<const BlendShapeTrack *>(t);
if (bst->compressed_track >= 0) { if (bst->compressed_track >= 0) {
_get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices); _get_compressed_key_indices_in_range<1>(bst->compressed_track, from_time, length, p_indices);
_get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length - CMP_EPSILON, p_indices); _get_compressed_key_indices_in_range<1>(bst->compressed_track, to_time, length, p_indices);
} else { } else {
_track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices, false); _track_get_key_indices_in_range(bst->blend_shapes, from_time, length, p_indices, false);
_track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices, true); _track_get_key_indices_in_range(bst->blend_shapes, to_time, length, p_indices, true);
@ -3109,9 +3109,9 @@ void Animation::track_get_key_indices_in_range(int p_track, double p_time, doubl
// The edge will be pingponged in the next frame and processed there, so let's ignore it now... // The edge will be pingponged in the next frame and processed there, so let's ignore it now...
if (!is_backward && Math::is_equal_approx(to_time, length)) { if (!is_backward && Math::is_equal_approx(to_time, length)) {
to_time = length - CMP_EPSILON; to_time -= CMP_EPSILON;
} else if (is_backward && Math::is_equal_approx(from_time, 0)) { } else if (is_backward && Math::is_equal_approx(from_time, 0)) {
from_time = CMP_EPSILON; from_time += CMP_EPSILON;
} }
} break; } break;
} }
@ -3818,7 +3818,7 @@ void Animation::_bind_methods() {
ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count); ClassDB::bind_method(D_METHOD("track_get_key_count", "track_idx"), &Animation::track_get_key_count);
ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value); ClassDB::bind_method(D_METHOD("track_get_key_value", "track_idx", "key_idx"), &Animation::track_get_key_value);
ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time); ClassDB::bind_method(D_METHOD("track_get_key_time", "track_idx", "key_idx"), &Animation::track_get_key_time);
ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "exact"), &Animation::track_find_key, DEFVAL(false)); ClassDB::bind_method(D_METHOD("track_find_key", "track_idx", "time", "find_mode"), &Animation::track_find_key, DEFVAL(FIND_MODE_NEAREST));
ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type); ClassDB::bind_method(D_METHOD("track_set_interpolation_type", "track_idx", "interpolation"), &Animation::track_set_interpolation_type);
ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type); ClassDB::bind_method(D_METHOD("track_get_interpolation_type", "track_idx"), &Animation::track_get_interpolation_type);
@ -3905,6 +3905,10 @@ void Animation::_bind_methods() {
BIND_ENUM_CONSTANT(LOOPED_FLAG_NONE); BIND_ENUM_CONSTANT(LOOPED_FLAG_NONE);
BIND_ENUM_CONSTANT(LOOPED_FLAG_END); BIND_ENUM_CONSTANT(LOOPED_FLAG_END);
BIND_ENUM_CONSTANT(LOOPED_FLAG_START); BIND_ENUM_CONSTANT(LOOPED_FLAG_START);
BIND_ENUM_CONSTANT(FIND_MODE_NEAREST);
BIND_ENUM_CONSTANT(FIND_MODE_APPROX);
BIND_ENUM_CONSTANT(FIND_MODE_EXACT);
} }
void Animation::clear() { void Animation::clear() {

View File

@ -79,6 +79,12 @@ public:
LOOPED_FLAG_START, LOOPED_FLAG_START,
}; };
enum FindMode {
FIND_MODE_NEAREST,
FIND_MODE_APPROX,
FIND_MODE_EXACT,
};
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
enum HandleMode { enum HandleMode {
HANDLE_MODE_FREE, HANDLE_MODE_FREE,
@ -392,7 +398,7 @@ public:
void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition); void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition);
void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value);
void track_set_key_time(int p_track, int p_key_idx, double p_time); void track_set_key_time(int p_track, int p_key_idx, double p_time);
int track_find_key(int p_track, double p_time, bool p_exact = false) const; int track_find_key(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST) const;
void track_remove_key(int p_track, int p_idx); void track_remove_key(int p_track, int p_idx);
void track_remove_key_at_time(int p_track, double p_time); void track_remove_key_at_time(int p_track, double p_time);
int track_get_key_count(int p_track) const; int track_get_key_count(int p_track) const;
@ -489,6 +495,7 @@ VARIANT_ENUM_CAST(Animation::InterpolationType);
VARIANT_ENUM_CAST(Animation::UpdateMode); VARIANT_ENUM_CAST(Animation::UpdateMode);
VARIANT_ENUM_CAST(Animation::LoopMode); VARIANT_ENUM_CAST(Animation::LoopMode);
VARIANT_ENUM_CAST(Animation::LoopedFlag); VARIANT_ENUM_CAST(Animation::LoopedFlag);
VARIANT_ENUM_CAST(Animation::FindMode);
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
VARIANT_ENUM_CAST(Animation::HandleMode); VARIANT_ENUM_CAST(Animation::HandleMode);
VARIANT_ENUM_CAST(Animation::HandleSetMode); VARIANT_ENUM_CAST(Animation::HandleSetMode);