Path: blob/master/editor/animation/animation_track_editor_plugins.cpp
9898 views
/**************************************************************************/1/* animation_track_editor_plugins.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "animation_track_editor_plugins.h"3132#include "editor/audio/audio_stream_preview.h"33#include "editor/editor_string_names.h"34#include "editor/editor_undo_redo_manager.h"35#include "editor/inspector/editor_resource_preview.h"36#include "editor/themes/editor_scale.h"37#include "scene/2d/animated_sprite_2d.h"38#include "scene/2d/sprite_2d.h"39#include "scene/3d/sprite_3d.h"40#include "scene/animation/animation_player.h"41#include "servers/audio/audio_stream.h"4243/// BOOL ///44int AnimationTrackEditBool::get_key_height() const {45Ref<Texture2D> checked = get_theme_icon(SNAME("checked"), SNAME("CheckBox"));46return checked->get_height();47}4849Rect2 AnimationTrackEditBool::get_key_rect(int p_index, float p_pixels_sec) {50Ref<Texture2D> checked = get_theme_icon(SNAME("checked"), SNAME("CheckBox"));51return Rect2(-checked->get_width() / 2, 0, checked->get_width(), get_size().height);52}5354bool AnimationTrackEditBool::is_key_selectable_by_distance() const {55return false;56}5758void AnimationTrackEditBool::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {59bool checked = get_animation()->track_get_key_value(get_track(), p_index);60Ref<Texture2D> icon = get_theme_icon(checked ? "checked" : "unchecked", "CheckBox");6162Vector2 ofs(p_x - icon->get_width() / 2, int(get_size().height - icon->get_height()) / 2);6364if (ofs.x + icon->get_width() / 2 < p_clip_left) {65return;66}6768if (ofs.x + icon->get_width() / 2 > p_clip_right) {69return;70}7172draw_texture(icon, ofs);7374if (p_selected) {75Color color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));76draw_rect_clipped(Rect2(ofs, icon->get_size()), color, false);77}78}7980/// COLOR ///8182int AnimationTrackEditColor::get_key_height() const {83Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));84int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));85return font->get_height(font_size) * 0.8;86}8788Rect2 AnimationTrackEditColor::get_key_rect(int p_index, float p_pixels_sec) {89Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));90int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));91int fh = font->get_height(font_size) * 0.8;92return Rect2(-fh / 2, 0, fh, get_size().height);93}9495bool AnimationTrackEditColor::is_key_selectable_by_distance() const {96return false;97}9899void AnimationTrackEditColor::draw_key_link(int p_index, float p_pixels_sec, int p_x, int p_next_x, int p_clip_left, int p_clip_right) {100Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));101int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));102int fh = (font->get_height(font_size) * 0.8);103104fh /= 3;105106int x_from = p_x + fh / 2 - 1;107int x_to = p_next_x - fh / 2 + 1;108x_from = MAX(x_from, p_clip_left);109x_to = MIN(x_to, p_clip_right);110111int y_from = (get_size().height - fh) / 2;112113if (x_from > p_clip_right || x_to < p_clip_left) {114return;115}116117Vector<Color> color_samples;118color_samples.append(get_animation()->track_get_key_value(get_track(), p_index));119120if (get_animation()->track_get_type(get_track()) == Animation::TYPE_VALUE) {121if (get_animation()->track_get_interpolation_type(get_track()) != Animation::INTERPOLATION_NEAREST &&122(get_animation()->value_track_get_update_mode(get_track()) == Animation::UPDATE_CONTINUOUS ||123get_animation()->value_track_get_update_mode(get_track()) == Animation::UPDATE_CAPTURE) &&124!Math::is_zero_approx(get_animation()->track_get_key_transition(get_track(), p_index))) {125float start_time = get_animation()->track_get_key_time(get_track(), p_index);126float end_time = get_animation()->track_get_key_time(get_track(), p_index + 1);127128Color color_next = get_animation()->value_track_interpolate(get_track(), end_time);129130if (!color_samples[0].is_equal_approx(color_next)) {131color_samples.resize(1 + (x_to - x_from) / 64); // Make a color sample every 64 px.132for (int i = 1; i < color_samples.size(); i++) {133float j = i;134color_samples.write[i] = get_animation()->value_track_interpolate(135get_track(),136Math::lerp(start_time, end_time, j / color_samples.size()));137}138}139color_samples.append(color_next);140} else {141color_samples.append(color_samples[0]);142}143} else {144color_samples.append(get_animation()->track_get_key_value(get_track(), p_index + 1));145}146147for (int i = 0; i < color_samples.size() - 1; i++) {148Vector<Vector2> points = {149Vector2(Math::lerp(x_from, x_to, float(i) / (color_samples.size() - 1)), y_from),150Vector2(Math::lerp(x_from, x_to, float(i + 1) / (color_samples.size() - 1)), y_from),151Vector2(Math::lerp(x_from, x_to, float(i + 1) / (color_samples.size() - 1)), y_from + fh),152Vector2(Math::lerp(x_from, x_to, float(i) / (color_samples.size() - 1)), y_from + fh)153};154155Vector<Color> colors = {156color_samples[i],157color_samples[i + 1],158color_samples[i + 1],159color_samples[i]160};161162draw_primitive(points, colors, Vector<Vector2>());163}164}165166void AnimationTrackEditColor::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {167Color color = get_animation()->track_get_key_value(get_track(), p_index);168169Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));170int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));171int fh = font->get_height(font_size) * 0.8;172173Rect2 rect(Vector2(p_x - fh / 2, int(get_size().height - fh) / 2), Size2(fh, fh));174175draw_rect_clipped(Rect2(rect.position, rect.size / 2), Color(0.4, 0.4, 0.4));176draw_rect_clipped(Rect2(rect.position + rect.size / 2, rect.size / 2), Color(0.4, 0.4, 0.4));177draw_rect_clipped(Rect2(rect.position + Vector2(rect.size.x / 2, 0), rect.size / 2), Color(0.6, 0.6, 0.6));178draw_rect_clipped(Rect2(rect.position + Vector2(0, rect.size.y / 2), rect.size / 2), Color(0.6, 0.6, 0.6));179draw_rect_clipped(rect, color);180181if (p_selected) {182Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));183draw_rect_clipped(rect, accent, false);184}185}186187/// AUDIO ///188189void AnimationTrackEditAudio::_preview_changed(ObjectID p_which) {190Object *object = ObjectDB::get_instance(id);191192if (!object) {193return;194}195196Ref<AudioStream> stream = object->call("get_stream");197198if (stream.is_valid() && stream->get_instance_id() == p_which) {199queue_redraw();200}201}202203int AnimationTrackEditAudio::get_key_height() const {204if (!ObjectDB::get_instance(id)) {205return AnimationTrackEdit::get_key_height();206}207208Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));209int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));210return int(font->get_height(font_size) * 1.5);211}212213Rect2 AnimationTrackEditAudio::get_key_rect(int p_index, float p_pixels_sec) {214Object *object = ObjectDB::get_instance(id);215216if (!object) {217return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);218}219220Ref<AudioStream> stream = object->call("get_stream");221222if (stream.is_null()) {223return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);224}225226bool play = get_animation()->track_get_key_value(get_track(), p_index);227if (play) {228float len = stream->get_length();229230if (len == 0) {231Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);232len = preview->get_length();233}234235if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {236len = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));237}238239return Rect2(0, 0, len * p_pixels_sec, get_size().height);240} else {241Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));242int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));243int fh = font->get_height(font_size) * 0.8;244return Rect2(0, 0, fh, get_size().height);245}246}247248bool AnimationTrackEditAudio::is_key_selectable_by_distance() const {249return false;250}251252void AnimationTrackEditAudio::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {253Object *object = ObjectDB::get_instance(id);254255if (!object) {256AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);257return;258}259260Ref<AudioStream> stream = object->call("get_stream");261262if (stream.is_null()) {263AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);264return;265}266267bool play = get_animation()->track_get_key_value(get_track(), p_index);268if (play) {269float len = stream->get_length();270271Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);272273float preview_len = preview->get_length();274275if (len == 0) {276len = preview_len;277}278279int pixel_len = len * p_pixels_sec;280281int pixel_begin = p_x;282int pixel_end = p_x + pixel_len;283284if (pixel_end < p_clip_left) {285return;286}287288if (pixel_begin > p_clip_right) {289return;290}291292int from_x = MAX(pixel_begin, p_clip_left);293int to_x = MIN(pixel_end, p_clip_right);294295if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {296float limit = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));297int limit_x = pixel_begin + limit * p_pixels_sec;298to_x = MIN(limit_x, to_x);299}300301if (to_x <= from_x) {302return;303}304305Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));306int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));307float fh = int(font->get_height(font_size) * 1.5);308Rect2 rect = Rect2(from_x, (get_size().height - fh) / 2, to_x - from_x, fh);309draw_rect(rect, Color(0.25, 0.25, 0.25));310311Vector<Vector2> points;312points.resize((to_x - from_x) * 2);313preview_len = preview->get_length();314315for (int i = from_x; i < to_x; i++) {316float ofs = (i - pixel_begin) * preview_len / pixel_len;317float ofs_n = ((i + 1) - pixel_begin) * preview_len / pixel_len;318float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5;319float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5;320321int idx = i - from_x;322points.write[idx * 2 + 0] = Vector2(i, rect.position.y + min * rect.size.y);323points.write[idx * 2 + 1] = Vector2(i, rect.position.y + max * rect.size.y);324}325326Vector<Color> colors = { Color(0.75, 0.75, 0.75) };327328RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), points, colors);329330if (p_selected) {331Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));332draw_rect(rect, accent, false);333}334} else {335Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));336int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));337int fh = font->get_height(font_size) * 0.8;338Rect2 rect(Vector2(p_x, int(get_size().height - fh) / 2), Size2(fh, fh));339340Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));341draw_rect_clipped(rect, color);342343if (p_selected) {344Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));345draw_rect_clipped(rect, accent, false);346}347}348}349350void AnimationTrackEditAudio::set_node(Object *p_object) {351id = p_object->get_instance_id();352}353354AnimationTrackEditAudio::AnimationTrackEditAudio() {355AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", callable_mp(this, &AnimationTrackEditAudio::_preview_changed));356}357358/// SPRITE FRAME / FRAME_COORDS ///359360int AnimationTrackEditSpriteFrame::get_key_height() const {361if (!ObjectDB::get_instance(id)) {362return AnimationTrackEdit::get_key_height();363}364365Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));366int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));367return int(font->get_height(font_size) * 2);368}369370Rect2 AnimationTrackEditSpriteFrame::get_key_rect(int p_index, float p_pixels_sec) {371Object *object = ObjectDB::get_instance(id);372373if (!object) {374return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);375}376377Size2 size;378379if (Object::cast_to<Sprite2D>(object) || Object::cast_to<Sprite3D>(object)) {380Ref<Texture2D> texture = object->call("get_texture");381if (texture.is_null()) {382return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);383}384385size = texture->get_size();386387if (bool(object->call("is_region_enabled"))) {388size = Rect2(object->call("get_region_rect")).size;389}390391int hframes = object->call("get_hframes");392int vframes = object->call("get_vframes");393394if (hframes > 1) {395size.x /= hframes;396}397if (vframes > 1) {398size.y /= vframes;399}400} else if (Object::cast_to<AnimatedSprite2D>(object) || Object::cast_to<AnimatedSprite3D>(object)) {401Ref<SpriteFrames> sf = object->call("get_sprite_frames");402if (sf.is_null()) {403return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);404}405406List<StringName> animations;407sf->get_animation_list(&animations);408409int frame = get_animation()->track_get_key_value(get_track(), p_index);410String animation_name;411if (animations.size() == 1) {412animation_name = animations.front()->get();413} else {414// Go through other track to find if animation is set415String animation_path = String(get_animation()->track_get_path(get_track()));416animation_path = animation_path.replace(":frame", ":animation");417int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track()));418float track_time = get_animation()->track_get_key_time(get_track(), p_index);419int animation_index = get_animation()->track_find_key(animation_track, track_time);420animation_name = get_animation()->track_get_key_value(animation_track, animation_index);421}422423Ref<Texture2D> texture = sf->get_frame_texture(animation_name, frame);424if (texture.is_null()) {425return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);426}427428size = texture->get_size();429}430431size = size.floor();432433Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));434int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));435int height = int(font->get_height(font_size) * 2);436int width = height * size.width / size.height;437438return Rect2(0, 0, width, get_size().height);439}440441bool AnimationTrackEditSpriteFrame::is_key_selectable_by_distance() const {442return false;443}444445void AnimationTrackEditSpriteFrame::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {446Object *object = ObjectDB::get_instance(id);447448if (!object) {449AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);450return;451}452453Ref<Texture2D> texture;454Rect2 region;455456if (Object::cast_to<Sprite2D>(object) || Object::cast_to<Sprite3D>(object)) {457texture = object->call("get_texture");458if (texture.is_null()) {459AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);460return;461}462463int hframes = object->call("get_hframes");464int vframes = object->call("get_vframes");465466Vector2 coords;467if (is_coords) {468coords = get_animation()->track_get_key_value(get_track(), p_index);469} else {470int frame = get_animation()->track_get_key_value(get_track(), p_index);471coords.x = frame % hframes;472coords.y = frame / hframes;473}474475region.size = texture->get_size();476477if (bool(object->call("is_region_enabled"))) {478region = Rect2(object->call("get_region_rect"));479}480481if (hframes > 1) {482region.size.x /= hframes;483}484if (vframes > 1) {485region.size.y /= vframes;486}487488region.position.x += region.size.x * coords.x;489region.position.y += region.size.y * coords.y;490491} else if (Object::cast_to<AnimatedSprite2D>(object) || Object::cast_to<AnimatedSprite3D>(object)) {492Ref<SpriteFrames> sf = object->call("get_sprite_frames");493if (sf.is_null()) {494AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);495return;496}497498List<StringName> animations;499sf->get_animation_list(&animations);500501int frame = get_animation()->track_get_key_value(get_track(), p_index);502String animation_name;503if (animations.size() == 1) {504animation_name = animations.front()->get();505} else {506// Go through other track to find if animation is set507String animation_path = String(get_animation()->track_get_path(get_track()));508animation_path = animation_path.replace(":frame", ":animation");509int animation_track = get_animation()->find_track(animation_path, get_animation()->track_get_type(get_track()));510float track_time = get_animation()->track_get_key_time(get_track(), p_index);511int animation_index = get_animation()->track_find_key(animation_track, track_time);512animation_name = get_animation()->track_get_key_value(animation_track, animation_index);513}514515texture = sf->get_frame_texture(animation_name, frame);516if (texture.is_null()) {517AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);518return;519}520521region.size = texture->get_size();522}523524Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));525int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));526int height = int(font->get_height(font_size) * 2);527528int width = height * region.size.width / region.size.height;529530Rect2 rect(p_x, int(get_size().height - height) / 2, width, height);531532if (rect.position.x + rect.size.x < p_clip_left) {533return;534}535536if (rect.position.x > p_clip_right) {537return;538}539540Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));541Color bg = accent;542bg.a = 0.15;543544draw_rect_clipped(rect, bg);545546draw_texture_region_clipped(texture, rect, region);547548if (p_selected) {549draw_rect_clipped(rect, accent, false);550}551}552553void AnimationTrackEditSpriteFrame::set_node(Object *p_object) {554id = p_object->get_instance_id();555}556557void AnimationTrackEditSpriteFrame::set_as_coords() {558is_coords = true;559}560561/// SUB ANIMATION ///562563int AnimationTrackEditSubAnim::get_key_height() const {564if (!ObjectDB::get_instance(id)) {565return AnimationTrackEdit::get_key_height();566}567568Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));569int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));570return int(font->get_height(font_size) * 1.5);571}572573Rect2 AnimationTrackEditSubAnim::get_key_rect(int p_index, float p_pixels_sec) {574Object *object = ObjectDB::get_instance(id);575576if (!object) {577return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);578}579580AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(object);581582if (!ap) {583return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);584}585586String anim = get_animation()->track_get_key_value(get_track(), p_index);587588if (anim != "[stop]" && ap->has_animation(anim)) {589float len = ap->get_animation(anim)->get_length();590591if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {592len = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));593}594595return Rect2(0, 0, len * p_pixels_sec, get_size().height);596} else {597Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));598int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));599int fh = font->get_height(font_size) * 0.8;600return Rect2(0, 0, fh, get_size().height);601}602}603604bool AnimationTrackEditSubAnim::is_key_selectable_by_distance() const {605return false;606}607608void AnimationTrackEditSubAnim::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {609Object *object = ObjectDB::get_instance(id);610611if (!object) {612AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);613return;614}615616AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(object);617618if (!ap) {619AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);620return;621}622623String anim = get_animation()->track_get_key_value(get_track(), p_index);624625if (anim != "[stop]" && ap->has_animation(anim)) {626float len = ap->get_animation(anim)->get_length();627628if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {629len = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));630}631632int pixel_len = len * p_pixels_sec;633634int pixel_begin = p_x;635int pixel_end = p_x + pixel_len;636637if (pixel_end < p_clip_left) {638return;639}640641if (pixel_begin > p_clip_right) {642return;643}644645int from_x = MAX(pixel_begin, p_clip_left);646int to_x = MIN(pixel_end, p_clip_right);647648if (to_x <= from_x) {649return;650}651652Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));653int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));654int fh = font->get_height(font_size) * 1.5;655656Rect2 rect(from_x, int(get_size().height - fh) / 2, to_x - from_x, fh);657658Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));659Color bg = color;660bg.r = 1 - color.r;661bg.g = 1 - color.g;662bg.b = 1 - color.b;663draw_rect(rect, bg);664665Vector<Vector2> points;666Vector<Color> colors = { color };667{668Ref<Animation> ap_anim = ap->get_animation(anim);669670for (int i = 0; i < ap_anim->get_track_count(); i++) {671float h = (rect.size.height - 2) / ap_anim->get_track_count();672673int y = 2 + h * i + h / 2;674675for (int j = 0; j < ap_anim->track_get_key_count(i); j++) {676float ofs = ap_anim->track_get_key_time(i, j);677int x = p_x + ofs * p_pixels_sec + 2;678679if (x < from_x || x >= (to_x - 4)) {680continue;681}682683points.push_back(Point2(x, y));684points.push_back(Point2(x + 1, y));685}686}687}688689if (points.size() > 2) {690RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), points, colors);691}692693int limit = to_x - from_x - 4;694if (limit > 0) {695draw_string(font, Point2(from_x + 2, int(get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size)), anim, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);696}697698if (p_selected) {699Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));700draw_rect(rect, accent, false);701}702} else {703Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));704int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));705int fh = font->get_height(font_size) * 0.8;706Rect2 rect(Vector2(p_x, int(get_size().height - fh) / 2), Size2(fh, fh));707708Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));709draw_rect_clipped(rect, color);710711if (p_selected) {712Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));713draw_rect_clipped(rect, accent, false);714}715}716}717718void AnimationTrackEditSubAnim::set_node(Object *p_object) {719id = p_object->get_instance_id();720}721722//// VOLUME DB ////723724int AnimationTrackEditVolumeDB::get_key_height() const {725Ref<Texture2D> volume_texture = get_editor_theme_icon(SNAME("ColorTrackVu"));726return volume_texture->get_height() * 1.2;727}728729void AnimationTrackEditVolumeDB::draw_bg(int p_clip_left, int p_clip_right) {730Ref<Texture2D> volume_texture = get_editor_theme_icon(SNAME("ColorTrackVu"));731int tex_h = volume_texture->get_height();732733int y_from = (get_size().height - tex_h) / 2;734int y_size = tex_h;735736Color color(1, 1, 1, 0.3);737draw_texture_rect(volume_texture, Rect2(p_clip_left, y_from, p_clip_right - p_clip_left, y_from + y_size), false, color);738}739740void AnimationTrackEditVolumeDB::draw_fg(int p_clip_left, int p_clip_right) {741Ref<Texture2D> volume_texture = get_editor_theme_icon(SNAME("ColorTrackVu"));742int tex_h = volume_texture->get_height();743int y_from = (get_size().height - tex_h) / 2;744int db0 = y_from + (24 / 80.0) * tex_h;745746draw_line(Vector2(p_clip_left, db0), Vector2(p_clip_right, db0), Color(1, 1, 1, 0.3));747}748749void AnimationTrackEditVolumeDB::draw_key_link(int p_index, float p_pixels_sec, int p_x, int p_next_x, int p_clip_left, int p_clip_right) {750if (p_x > p_clip_right || p_next_x < p_clip_left) {751return;752}753754float db = get_animation()->track_get_key_value(get_track(), p_index);755float db_n = get_animation()->track_get_key_value(get_track(), p_index + 1);756757db = CLAMP(db, -60, 24);758db_n = CLAMP(db_n, -60, 24);759760float h = 1.0 - ((db + 60) / 84.0);761float h_n = 1.0 - ((db_n + 60) / 84.0);762763int from_x = p_x;764int to_x = p_next_x;765766if (from_x < p_clip_left) {767h = Math::lerp(h, h_n, float(p_clip_left - from_x) / float(to_x - from_x));768from_x = p_clip_left;769}770771if (to_x > p_clip_right) {772h_n = Math::lerp(h, h_n, float(p_clip_right - from_x) / float(to_x - from_x));773to_x = p_clip_right;774}775776Ref<Texture2D> volume_texture = get_editor_theme_icon(SNAME("ColorTrackVu"));777int tex_h = volume_texture->get_height();778779int y_from = (get_size().height - tex_h) / 2;780781Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));782color.a *= 0.7;783784draw_line(Point2(from_x, y_from + h * tex_h), Point2(to_x, y_from + h_n * tex_h), color, 2);785}786787////////////////////////788789/// AUDIO ///790791void AnimationTrackEditTypeAudio::_preview_changed(ObjectID p_which) {792for (int i = 0; i < get_animation()->track_get_key_count(get_track()); i++) {793Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), i);794if (stream.is_valid() && stream->get_instance_id() == p_which) {795queue_redraw();796return;797}798}799}800801int AnimationTrackEditTypeAudio::get_key_height() const {802Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));803int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));804return int(font->get_height(font_size) * 1.5);805}806807Rect2 AnimationTrackEditTypeAudio::get_key_rect(int p_index, float p_pixels_sec) {808Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), p_index);809810if (stream.is_null()) {811return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);812}813814float start_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), p_index);815float end_ofs = get_animation()->audio_track_get_key_end_offset(get_track(), p_index);816817float len = stream->get_length();818819if (len == 0) {820Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);821len = preview->get_length();822}823824len -= end_ofs;825len -= start_ofs;826if (len <= 0.0001) {827len = 0.0001;828}829830if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {831len = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));832}833834return Rect2(0, 0, len * p_pixels_sec, get_size().height);835}836837bool AnimationTrackEditTypeAudio::is_key_selectable_by_distance() const {838return false;839}840841void AnimationTrackEditTypeAudio::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {842Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), p_index);843if (stream.is_null()) {844AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right); // Draw diamond.845return;846}847848float len = stream->get_length();849if (len == 0) {850AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right); // Draw diamond.851return;852}853854float start_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), p_index);855float end_ofs = get_animation()->audio_track_get_key_end_offset(get_track(), p_index);856857int px_offset = 0;858if (len_resizing && p_index == len_resizing_index) {859float ofs_local = len_resizing_rel / get_timeline()->get_zoom_scale();860if (len_resizing_start) {861start_ofs += ofs_local;862px_offset = ofs_local * p_pixels_sec;863} else {864end_ofs -= ofs_local;865}866}867868Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));869int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));870float fh = int(font->get_height(font_size) * 1.5);871872Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);873874int pixel_total_len = len * p_pixels_sec;875876len -= end_ofs;877len -= start_ofs;878879if (len <= 0.0001) {880len = 0.0001;881}882883int pixel_len = len * p_pixels_sec;884885int pixel_begin = px_offset + p_x;886int pixel_end = px_offset + p_x + pixel_len;887888if (pixel_end < p_clip_left) {889return;890}891892if (pixel_begin > p_clip_right) {893return;894}895896int from_x = MAX(pixel_begin, p_clip_left);897int to_x = MIN(pixel_end, p_clip_right);898899if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {900float limit = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));901int limit_x = pixel_begin + limit * p_pixels_sec;902to_x = MIN(limit_x, to_x);903}904905if (to_x <= from_x) {906to_x = from_x + 1;907}908909int h = get_size().height;910Rect2 rect = Rect2(from_x, (h - fh) / 2, to_x - from_x, fh);911draw_rect(rect, Color(0.25, 0.25, 0.25));912913Vector<Vector2> points;914points.resize((to_x - from_x) * 2);915float preview_len = preview->get_length();916917for (int i = from_x; i < to_x; i++) {918float ofs = (i - pixel_begin) * preview_len / pixel_total_len;919float ofs_n = ((i + 1) - pixel_begin) * preview_len / pixel_total_len;920ofs += start_ofs;921ofs_n += start_ofs;922923float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5;924float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5;925926int idx = i - from_x;927points.write[idx * 2 + 0] = Vector2(i, rect.position.y + min * rect.size.y);928points.write[idx * 2 + 1] = Vector2(i, rect.position.y + max * rect.size.y);929}930931Vector<Color> colors = { Color(0.75, 0.75, 0.75) };932933RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), points, colors);934935Color cut_color = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));936cut_color.a = 0.7;937if (start_ofs > 0 && pixel_begin > p_clip_left) {938draw_rect(Rect2(pixel_begin, rect.position.y, 1, rect.size.y), cut_color);939}940if (end_ofs > 0 && pixel_end < p_clip_right) {941draw_rect(Rect2(pixel_end, rect.position.y, 1, rect.size.y), cut_color);942}943944if (p_selected) {945Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));946draw_rect(rect, accent, false);947}948}949950AnimationTrackEditTypeAudio::AnimationTrackEditTypeAudio() {951AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", callable_mp(this, &AnimationTrackEditTypeAudio::_preview_changed));952}953954bool AnimationTrackEditTypeAudio::can_drop_data(const Point2 &p_point, const Variant &p_data) const {955if (p_point.x > get_timeline()->get_name_limit() && p_point.x < get_size().width - get_timeline()->get_buttons_width()) {956Dictionary drag_data = p_data;957if (drag_data.has("type") && String(drag_data["type"]) == "resource") {958Ref<AudioStream> res = drag_data["resource"];959if (res.is_valid()) {960return true;961}962}963964if (drag_data.has("type") && String(drag_data["type"]) == "files") {965Vector<String> files = drag_data["files"];966967if (files.size() == 1) {968Ref<AudioStream> res = ResourceLoader::load(files[0]);969if (res.is_valid()) {970return true;971}972}973}974}975976return AnimationTrackEdit::can_drop_data(p_point, p_data);977}978979void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant &p_data) {980if (p_point.x > get_timeline()->get_name_limit() && p_point.x < get_size().width - get_timeline()->get_buttons_width()) {981Ref<AudioStream> stream;982Dictionary drag_data = p_data;983if (drag_data.has("type") && String(drag_data["type"]) == "resource") {984stream = drag_data["resource"];985} else if (drag_data.has("type") && String(drag_data["type"]) == "files") {986Vector<String> files = drag_data["files"];987988if (files.size() == 1) {989stream = ResourceLoader::load(files[0]);990}991}992993if (stream.is_valid()) {994int x = p_point.x - get_timeline()->get_name_limit();995float ofs = x / get_timeline()->get_zoom_scale();996ofs += get_timeline()->get_value();997998ofs = get_editor()->snap_time(ofs);9991000while (get_animation()->track_find_key(get_track(), ofs, Animation::FIND_MODE_APPROX) != -1) { //make sure insertion point is valid1001ofs += 0.0001;1002}10031004EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();1005undo_redo->create_action(TTR("Add Audio Track Clip"));1006undo_redo->add_do_method(get_animation().ptr(), "audio_track_insert_key", get_track(), ofs, stream);1007undo_redo->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);1008undo_redo->commit_action();10091010queue_redraw();1011return;1012}1013}10141015AnimationTrackEdit::drop_data(p_point, p_data);1016}10171018void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {1019ERR_FAIL_COND(p_event.is_null());10201021Ref<InputEventMouseMotion> mm = p_event;1022if (!len_resizing && mm.is_valid()) {1023bool use_hsize_cursor = false;1024for (int i = 0; i < get_animation()->track_get_key_count(get_track()); i++) {1025Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), i);10261027if (stream.is_null()) {1028continue;1029}10301031float len = stream->get_length();1032if (len == 0) {1033continue;1034}10351036float start_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), i);1037float end_ofs = get_animation()->audio_track_get_key_end_offset(get_track(), i);1038len -= end_ofs;1039len -= start_ofs;10401041if (get_animation()->track_get_key_count(get_track()) > i + 1) {1042len = MIN(len, get_animation()->track_get_key_time(get_track(), i + 1) - get_animation()->track_get_key_time(get_track(), i));1043}10441045float ofs = get_animation()->track_get_key_time(get_track(), i);10461047ofs -= get_timeline()->get_value();1048ofs *= get_timeline()->get_zoom_scale();1049ofs += get_timeline()->get_name_limit();10501051int end = ofs + len * get_timeline()->get_zoom_scale();10521053if (end >= get_timeline()->get_name_limit() && end <= get_size().width - get_timeline()->get_buttons_width() && Math::abs(mm->get_position().x - end) < 5 * EDSCALE) {1054len_resizing_start = false;1055use_hsize_cursor = true;1056len_resizing_index = i;1057}10581059if (ofs >= get_timeline()->get_name_limit() && ofs <= get_size().width - get_timeline()->get_buttons_width() && Math::abs(mm->get_position().x - ofs) < 5 * EDSCALE) {1060len_resizing_start = true;1061use_hsize_cursor = true;1062len_resizing_index = i;1063}1064}1065over_drag_position = use_hsize_cursor;1066}10671068if (len_resizing && mm.is_valid()) {1069// Rezising index is some.1070len_resizing_rel += mm->get_relative().x;1071float ofs_local = len_resizing_rel / get_timeline()->get_zoom_scale();1072float prev_ofs_start = get_animation()->audio_track_get_key_start_offset(get_track(), len_resizing_index);1073float prev_ofs_end = get_animation()->audio_track_get_key_end_offset(get_track(), len_resizing_index);1074Ref<AudioStream> stream = get_animation()->audio_track_get_key_stream(get_track(), len_resizing_index);1075float len = stream->get_length();1076if (len == 0) {1077Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream);1078float preview_len = preview->get_length();1079len = preview_len;1080}10811082if (len_resizing_start) {1083len_resizing_rel = CLAMP(ofs_local, -prev_ofs_start, len - prev_ofs_end - prev_ofs_start) * get_timeline()->get_zoom_scale();1084} else {1085len_resizing_rel = CLAMP(ofs_local, -(len - prev_ofs_end - prev_ofs_start), prev_ofs_end) * get_timeline()->get_zoom_scale();1086}10871088queue_redraw();1089accept_event();1090return;1091}10921093Ref<InputEventMouseButton> mb = p_event;1094if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && over_drag_position) {1095len_resizing = true;1096// In case if resizing index is not set yet reset the flag.1097if (len_resizing_index < 0) {1098len_resizing = false;1099return;1100}1101len_resizing_from_px = mb->get_position().x;1102len_resizing_rel = 0;1103queue_redraw();1104accept_event();1105return;1106}11071108EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();1109if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {1110if (len_resizing_rel == 0 || len_resizing_index < 0) {1111len_resizing = false;1112return;1113}11141115if (len_resizing_start) {1116float ofs_local = len_resizing_rel / get_timeline()->get_zoom_scale();1117float prev_ofs = get_animation()->audio_track_get_key_start_offset(get_track(), len_resizing_index);1118float prev_time = get_animation()->track_get_key_time(get_track(), len_resizing_index);1119float new_ofs = prev_ofs + ofs_local;1120float new_time = prev_time + ofs_local;1121if (prev_time != new_time) {1122undo_redo->create_action(TTR("Change Audio Track Clip Start Offset"));11231124undo_redo->add_do_method(get_animation().ptr(), "track_set_key_time", get_track(), len_resizing_index, new_time);1125undo_redo->add_undo_method(get_animation().ptr(), "track_set_key_time", get_track(), len_resizing_index, prev_time);11261127undo_redo->add_do_method(get_animation().ptr(), "audio_track_set_key_start_offset", get_track(), len_resizing_index, new_ofs);1128undo_redo->add_undo_method(get_animation().ptr(), "audio_track_set_key_start_offset", get_track(), len_resizing_index, prev_ofs);11291130undo_redo->commit_action();1131}1132} else {1133float ofs_local = -len_resizing_rel / get_timeline()->get_zoom_scale();1134float prev_ofs = get_animation()->audio_track_get_key_end_offset(get_track(), len_resizing_index);1135float new_ofs = prev_ofs + ofs_local;1136if (prev_ofs != new_ofs) {1137undo_redo->create_action(TTR("Change Audio Track Clip End Offset"));1138undo_redo->add_do_method(get_animation().ptr(), "audio_track_set_key_end_offset", get_track(), len_resizing_index, new_ofs);1139undo_redo->add_undo_method(get_animation().ptr(), "audio_track_set_key_end_offset", get_track(), len_resizing_index, prev_ofs);1140undo_redo->commit_action();1141}1142}11431144len_resizing_index = -1;1145len_resizing = false;1146queue_redraw();1147accept_event();1148return;1149}11501151AnimationTrackEdit::gui_input(p_event);1152}11531154Control::CursorShape AnimationTrackEditTypeAudio::get_cursor_shape(const Point2 &p_pos) const {1155if (over_drag_position || len_resizing) {1156return Control::CURSOR_HSIZE;1157} else {1158return get_default_cursor_shape();1159}1160}11611162////////////////////1163/// SUB ANIMATION ///11641165int AnimationTrackEditTypeAnimation::get_key_height() const {1166if (!ObjectDB::get_instance(id)) {1167return AnimationTrackEdit::get_key_height();1168}11691170Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));1171int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1172return int(font->get_height(font_size) * 1.5);1173}11741175Rect2 AnimationTrackEditTypeAnimation::get_key_rect(int p_index, float p_pixels_sec) {1176Object *object = ObjectDB::get_instance(id);11771178if (!object) {1179return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);1180}11811182AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(object);11831184if (!ap) {1185return AnimationTrackEdit::get_key_rect(p_index, p_pixels_sec);1186}11871188String anim = get_animation()->animation_track_get_key_animation(get_track(), p_index);11891190if (anim != "[stop]" && ap->has_animation(anim)) {1191float len = ap->get_animation(anim)->get_length();11921193if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {1194len = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));1195}11961197return Rect2(0, 0, len * p_pixels_sec, get_size().height);1198} else {1199Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));1200int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1201int fh = font->get_height(font_size) * 0.8;1202return Rect2(0, 0, fh, get_size().height);1203}1204}12051206bool AnimationTrackEditTypeAnimation::is_key_selectable_by_distance() const {1207return false;1208}12091210void AnimationTrackEditTypeAnimation::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {1211Object *object = ObjectDB::get_instance(id);12121213if (!object) {1214AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);1215return;1216}12171218AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(object);12191220if (!ap) {1221AnimationTrackEdit::draw_key(p_index, p_pixels_sec, p_x, p_selected, p_clip_left, p_clip_right);1222return;1223}12241225String anim = get_animation()->animation_track_get_key_animation(get_track(), p_index);12261227if (anim != "[stop]" && ap->has_animation(anim)) {1228float len = ap->get_animation(anim)->get_length();12291230if (get_animation()->track_get_key_count(get_track()) > p_index + 1) {1231len = MIN(len, get_animation()->track_get_key_time(get_track(), p_index + 1) - get_animation()->track_get_key_time(get_track(), p_index));1232}12331234int pixel_len = len * p_pixels_sec;12351236int pixel_begin = p_x;1237int pixel_end = p_x + pixel_len;12381239if (pixel_end < p_clip_left) {1240return;1241}12421243if (pixel_begin > p_clip_right) {1244return;1245}12461247int from_x = MAX(pixel_begin, p_clip_left);1248int to_x = MIN(pixel_end, p_clip_right);12491250if (to_x <= from_x) {1251return;1252}12531254Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));1255int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1256int fh = font->get_height(font_size) * 1.5;12571258Rect2 rect(from_x, int(get_size().height - fh) / 2, to_x - from_x, fh);12591260Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));1261Color bg = color;1262bg.r = 1 - color.r;1263bg.g = 1 - color.g;1264bg.b = 1 - color.b;1265draw_rect(rect, bg);12661267Vector<Vector2> points;1268Vector<Color> colors = { color };1269{1270Ref<Animation> ap_anim = ap->get_animation(anim);12711272for (int i = 0; i < ap_anim->get_track_count(); i++) {1273float h = (rect.size.height - 2) / ap_anim->get_track_count();12741275int y = 2 + h * i + h / 2;12761277for (int j = 0; j < ap_anim->track_get_key_count(i); j++) {1278float ofs = ap_anim->track_get_key_time(i, j);1279int x = p_x + ofs * p_pixels_sec + 2;12801281if (x < from_x || x >= (to_x - 4)) {1282continue;1283}12841285points.push_back(Point2(x, y));1286points.push_back(Point2(x + 1, y));1287}1288}1289}12901291if (points.size() > 2) {1292RS::get_singleton()->canvas_item_add_multiline(get_canvas_item(), points, colors);1293}12941295int limit = to_x - from_x - 4;1296if (limit > 0) {1297draw_string(font, Point2(from_x + 2, int(get_size().height - font->get_height(font_size)) / 2 + font->get_ascent(font_size)), anim, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, color);1298}12991300if (p_selected) {1301Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));1302draw_rect(rect, accent, false);1303}1304} else {1305Ref<Font> font = get_theme_font(SceneStringName(font), SNAME("Label"));1306int font_size = get_theme_font_size(SceneStringName(font_size), SNAME("Label"));1307int fh = font->get_height(font_size) * 0.8;1308Rect2 rect(Vector2(p_x, int(get_size().height - fh) / 2), Size2(fh, fh));13091310Color color = get_theme_color(SceneStringName(font_color), SNAME("Label"));1311draw_rect_clipped(rect, color);13121313if (p_selected) {1314Color accent = get_theme_color(SNAME("accent_color"), EditorStringName(Editor));1315draw_rect_clipped(rect, accent, false);1316}1317}1318}13191320void AnimationTrackEditTypeAnimation::set_node(Object *p_object) {1321id = p_object->get_instance_id();1322}13231324/////////1325AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_value_track_edit(Object *p_object, Variant::Type p_type, const String &p_property, PropertyHint p_hint, const String &p_hint_string, int p_usage) {1326if (p_property == "playing" && (p_object->is_class("AudioStreamPlayer") || p_object->is_class("AudioStreamPlayer2D") || p_object->is_class("AudioStreamPlayer3D"))) {1327AnimationTrackEditAudio *audio = memnew(AnimationTrackEditAudio);1328audio->set_node(p_object);1329return audio;1330}13311332if (p_property == "frame" && (p_object->is_class("Sprite2D") || p_object->is_class("Sprite3D") || p_object->is_class("AnimatedSprite2D") || p_object->is_class("AnimatedSprite3D"))) {1333AnimationTrackEditSpriteFrame *sprite = memnew(AnimationTrackEditSpriteFrame);1334sprite->set_node(p_object);1335return sprite;1336}13371338if (p_property == "frame_coords" && (p_object->is_class("Sprite2D") || p_object->is_class("Sprite3D"))) {1339AnimationTrackEditSpriteFrame *sprite = memnew(AnimationTrackEditSpriteFrame);1340sprite->set_as_coords();1341sprite->set_node(p_object);1342return sprite;1343}13441345if (p_property == "current_animation" && (p_object->is_class("AnimationPlayer"))) {1346AnimationTrackEditSubAnim *player = memnew(AnimationTrackEditSubAnim);1347player->set_node(p_object);1348return player;1349}13501351if (p_property == "volume_db") {1352AnimationTrackEditVolumeDB *vu = memnew(AnimationTrackEditVolumeDB);1353return vu;1354}13551356if (p_type == Variant::BOOL) {1357return memnew(AnimationTrackEditBool);1358}1359if (p_type == Variant::COLOR) {1360return memnew(AnimationTrackEditColor);1361}13621363return nullptr;1364}13651366AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_audio_track_edit() {1367return memnew(AnimationTrackEditTypeAudio);1368}13691370AnimationTrackEdit *AnimationTrackEditDefaultPlugin::create_animation_track_edit(Object *p_object) {1371AnimationTrackEditTypeAnimation *an = memnew(AnimationTrackEditTypeAnimation);1372an->set_node(p_object);1373return an;1374}137513761377