animation_bezier_editor.cpp 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693
  1. /*************************************************************************/
  2. /* animation_bezier_editor.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "animation_bezier_editor.h"
  31. #include "editor/editor_node.h"
  32. #include "editor/editor_scale.h"
  33. #include "editor/editor_undo_redo_manager.h"
  34. #include "scene/gui/view_panner.h"
  35. #include "scene/resources/text_line.h"
  36. #include <limits.h>
  37. float AnimationBezierTrackEdit::_bezier_h_to_pixel(float p_h) {
  38. float h = p_h;
  39. h = (h - v_scroll) / v_zoom;
  40. h = (get_size().height / 2.0) - h;
  41. return h;
  42. }
  43. void AnimationBezierTrackEdit::_draw_track(int p_track, const Color &p_color) {
  44. float scale = timeline->get_zoom_scale();
  45. int limit = timeline->get_name_limit();
  46. int right_limit = get_size().width;
  47. //selection may have altered the order of keys
  48. RBMap<real_t, int> key_order;
  49. for (int i = 0; i < animation->track_get_key_count(p_track); i++) {
  50. real_t ofs = animation->track_get_key_time(p_track, i);
  51. if (moving_selection && selection.has(IntPair(p_track, i))) {
  52. ofs += moving_selection_offset.x;
  53. }
  54. key_order[ofs] = i;
  55. }
  56. for (RBMap<real_t, int>::Element *E = key_order.front(); E; E = E->next()) {
  57. int i = E->get();
  58. if (!E->next()) {
  59. break;
  60. }
  61. int i_n = E->next()->get();
  62. float offset = animation->track_get_key_time(p_track, i);
  63. float height = animation->bezier_track_get_key_value(p_track, i);
  64. Vector2 out_handle = animation->bezier_track_get_key_out_handle(p_track, i);
  65. if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i) {
  66. out_handle = moving_handle_right;
  67. }
  68. if (moving_selection && selection.has(IntPair(p_track, i))) {
  69. offset += moving_selection_offset.x;
  70. height += moving_selection_offset.y;
  71. }
  72. out_handle += Vector2(offset, height);
  73. float offset_n = animation->track_get_key_time(p_track, i_n);
  74. float height_n = animation->bezier_track_get_key_value(p_track, i_n);
  75. Vector2 in_handle = animation->bezier_track_get_key_in_handle(p_track, i_n);
  76. if (p_track == moving_handle_track && (moving_handle == -1 || moving_handle == 1) && moving_handle_key == i_n) {
  77. in_handle = moving_handle_left;
  78. }
  79. if (moving_selection && selection.has(IntPair(p_track, i_n))) {
  80. offset_n += moving_selection_offset.x;
  81. height_n += moving_selection_offset.y;
  82. }
  83. in_handle += Vector2(offset_n, height_n);
  84. Vector2 start(offset, height);
  85. Vector2 end(offset_n, height_n);
  86. int from_x = (offset - timeline->get_value()) * scale + limit;
  87. int point_start = from_x;
  88. int to_x = (offset_n - timeline->get_value()) * scale + limit;
  89. int point_end = to_x;
  90. if (from_x > right_limit) { //not visible
  91. continue;
  92. }
  93. if (to_x < limit) { //not visible
  94. continue;
  95. }
  96. from_x = MAX(from_x, limit);
  97. to_x = MIN(to_x, right_limit);
  98. Vector<Vector2> lines;
  99. Vector2 prev_pos;
  100. for (int j = from_x; j <= to_x; j++) {
  101. float t = (j - limit) / scale + timeline->get_value();
  102. float h;
  103. if (j == point_end) {
  104. h = end.y; //make sure it always connects
  105. } else if (j == point_start) {
  106. h = start.y; //make sure it always connects
  107. } else { //custom interpolation, used because it needs to show paths affected by moving the selection or handles
  108. int iterations = 10;
  109. float low = 0;
  110. float high = 1;
  111. //narrow high and low as much as possible
  112. for (int k = 0; k < iterations; k++) {
  113. float middle = (low + high) / 2.0;
  114. Vector2 interp = start.bezier_interpolate(out_handle, in_handle, end, middle);
  115. if (interp.x < t) {
  116. low = middle;
  117. } else {
  118. high = middle;
  119. }
  120. }
  121. //interpolate the result:
  122. Vector2 low_pos = start.bezier_interpolate(out_handle, in_handle, end, low);
  123. Vector2 high_pos = start.bezier_interpolate(out_handle, in_handle, end, high);
  124. float c = (t - low_pos.x) / (high_pos.x - low_pos.x);
  125. h = low_pos.lerp(high_pos, c).y;
  126. }
  127. h = _bezier_h_to_pixel(h);
  128. Vector2 pos(j, h);
  129. if (j > from_x) {
  130. lines.push_back(prev_pos);
  131. lines.push_back(pos);
  132. }
  133. prev_pos = pos;
  134. }
  135. if (lines.size() >= 2) {
  136. draw_multiline(lines, p_color, Math::round(EDSCALE));
  137. }
  138. }
  139. }
  140. void AnimationBezierTrackEdit::_draw_line_clipped(const Vector2 &p_from, const Vector2 &p_to, const Color &p_color, int p_clip_left, int p_clip_right) {
  141. Vector2 from = p_from;
  142. Vector2 to = p_to;
  143. if (from.x == to.x && from.y == to.y) {
  144. return;
  145. }
  146. if (to.x < from.x) {
  147. SWAP(to, from);
  148. }
  149. if (to.x < p_clip_left) {
  150. return;
  151. }
  152. if (from.x > p_clip_right) {
  153. return;
  154. }
  155. if (to.x > p_clip_right) {
  156. float c = (p_clip_right - from.x) / (to.x - from.x);
  157. to = from.lerp(to, c);
  158. }
  159. if (from.x < p_clip_left) {
  160. float c = (p_clip_left - from.x) / (to.x - from.x);
  161. from = from.lerp(to, c);
  162. }
  163. draw_line(from, to, p_color, Math::round(EDSCALE));
  164. }
  165. void AnimationBezierTrackEdit::_notification(int p_what) {
  166. switch (p_what) {
  167. case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
  168. panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
  169. } break;
  170. case NOTIFICATION_ENTER_TREE: {
  171. panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/animation_editors_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
  172. [[fallthrough]];
  173. }
  174. case NOTIFICATION_THEME_CHANGED: {
  175. bezier_icon = get_theme_icon(SNAME("KeyBezierPoint"), SNAME("EditorIcons"));
  176. bezier_handle_icon = get_theme_icon(SNAME("KeyBezierHandle"), SNAME("EditorIcons"));
  177. selected_icon = get_theme_icon(SNAME("KeyBezierSelected"), SNAME("EditorIcons"));
  178. } break;
  179. case NOTIFICATION_DRAW: {
  180. if (animation.is_null()) {
  181. return;
  182. }
  183. int limit = timeline->get_name_limit();
  184. if (has_focus()) {
  185. Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
  186. accent.a *= 0.7;
  187. draw_rect(Rect2(Point2(), get_size()), accent, false, Math::round(EDSCALE));
  188. }
  189. Ref<Font> font = get_theme_font(SNAME("font"), SNAME("Label"));
  190. int font_size = get_theme_font_size(SNAME("font_size"), SNAME("Label"));
  191. Color color = get_theme_color(SNAME("font_color"), SNAME("Label"));
  192. int hsep = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
  193. int vsep = get_theme_constant(SNAME("v_separation"), SNAME("ItemList"));
  194. Color linecolor = color;
  195. linecolor.a = 0.2;
  196. draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE));
  197. int right_limit = get_size().width;
  198. int vofs = vsep;
  199. int margin = 0;
  200. RBMap<int, Color> subtrack_colors;
  201. Color selected_track_color;
  202. subtracks.clear();
  203. subtrack_icons.clear();
  204. RBMap<String, Vector<int>> track_indices;
  205. int track_count = animation->get_track_count();
  206. for (int i = 0; i < track_count; ++i) {
  207. if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) {
  208. continue;
  209. }
  210. String base_path = animation->track_get_path(i);
  211. if (is_filtered) {
  212. if (root && root->has_node(base_path)) {
  213. Node *node = root->get_node(base_path);
  214. if (!node) {
  215. continue; // No node, no filter.
  216. }
  217. if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
  218. continue; // Skip track due to not selected.
  219. }
  220. }
  221. }
  222. int end = base_path.find(":");
  223. if (end != -1) {
  224. base_path = base_path.substr(0, end + 1);
  225. }
  226. Vector<int> indices = track_indices.has(base_path) ? track_indices[base_path] : Vector<int>();
  227. indices.push_back(i);
  228. track_indices[base_path] = indices;
  229. }
  230. for (const KeyValue<String, Vector<int>> &E : track_indices) {
  231. String base_path = E.key;
  232. Vector<int> tracks = E.value;
  233. // NAMES AND ICON
  234. {
  235. NodePath path = animation->track_get_path(tracks[0]);
  236. Node *node = nullptr;
  237. if (root && root->has_node(path)) {
  238. node = root->get_node(path);
  239. }
  240. String text;
  241. if (node) {
  242. int ofs = 0;
  243. Ref<Texture2D> icon = EditorNode::get_singleton()->get_object_icon(node, "Node");
  244. text = node->get_name();
  245. ofs += hsep;
  246. TextLine text_buf = TextLine(text, font, font_size);
  247. text_buf.set_width(limit - ofs - icon->get_width() - hsep);
  248. int h = MAX(text_buf.get_size().y, icon->get_height());
  249. draw_texture(icon, Point2(ofs, vofs + int(h - icon->get_height()) / 2.0));
  250. ofs += icon->get_width();
  251. margin = icon->get_width();
  252. Vector2 string_pos = Point2(ofs, vofs);
  253. string_pos = string_pos.floor();
  254. text_buf.draw(get_canvas_item(), string_pos, color);
  255. vofs += h + vsep;
  256. }
  257. }
  258. Color dc = get_theme_color(SNAME("disabled_font_color"), SNAME("Editor"));
  259. Ref<Texture2D> remove = get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));
  260. float remove_hpos = limit - hsep - remove->get_width();
  261. Ref<Texture2D> lock = get_theme_icon(SNAME("Lock"), SNAME("EditorIcons"));
  262. Ref<Texture2D> unlock = get_theme_icon(SNAME("Unlock"), SNAME("EditorIcons"));
  263. float lock_hpos = remove_hpos - hsep - lock->get_width();
  264. Ref<Texture2D> visibility_visible = get_theme_icon(SNAME("GuiVisibilityVisible"), SNAME("EditorIcons"));
  265. Ref<Texture2D> visibility_hidden = get_theme_icon(SNAME("GuiVisibilityHidden"), SNAME("EditorIcons"));
  266. float visibility_hpos = lock_hpos - hsep - visibility_visible->get_width();
  267. Ref<Texture2D> solo = get_theme_icon(SNAME("AudioBusSolo"), SNAME("EditorIcons"));
  268. float solo_hpos = visibility_hpos - hsep - solo->get_width();
  269. float buttons_width = remove->get_width() + lock->get_width() + visibility_visible->get_width() + solo->get_width() + hsep * 3;
  270. for (int i = 0; i < tracks.size(); ++i) {
  271. // RELATED TRACKS TITLES
  272. int current_track = tracks[i];
  273. String path = animation->track_get_path(current_track);
  274. path = path.replace_first(base_path, "");
  275. Color cc = color;
  276. TextLine text_buf = TextLine(path, font, font_size);
  277. text_buf.set_width(limit - margin - buttons_width);
  278. Rect2 rect = Rect2(margin, vofs, solo_hpos - hsep - solo->get_width(), text_buf.get_size().y + vsep);
  279. cc.a *= 0.7;
  280. float h;
  281. if (path.ends_with(":x")) {
  282. h = 0;
  283. } else if (path.ends_with(":y")) {
  284. h = 0.33f;
  285. } else if (path.ends_with(":z")) {
  286. h = 0.66f;
  287. } else {
  288. uint32_t hash = path.hash();
  289. hash = ((hash >> 16) ^ hash) * 0x45d9f3b;
  290. hash = ((hash >> 16) ^ hash) * 0x45d9f3b;
  291. hash = (hash >> 16) ^ hash;
  292. h = (hash % 65535) / 65536.0;
  293. }
  294. if (current_track != selected_track) {
  295. Color track_color;
  296. if (locked_tracks.has(current_track)) {
  297. track_color.set_hsv(h, 0, 0.4);
  298. } else {
  299. track_color.set_hsv(h, 0.2, 0.8);
  300. }
  301. track_color.a = 0.5;
  302. draw_rect(Rect2(0, vofs, margin - hsep, text_buf.get_size().y * 0.8), track_color);
  303. subtrack_colors[current_track] = track_color;
  304. subtracks[current_track] = rect;
  305. } else {
  306. Color ac = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
  307. ac.a = 0.5;
  308. draw_rect(rect, ac);
  309. if (locked_tracks.has(selected_track)) {
  310. selected_track_color.set_hsv(h, 0.0, 0.4);
  311. } else {
  312. selected_track_color.set_hsv(h, 0.8, 0.8);
  313. }
  314. }
  315. Vector2 string_pos = Point2(margin, vofs);
  316. text_buf.draw(get_canvas_item(), string_pos, cc);
  317. float icon_start_height = vofs + rect.size.y / 2.0;
  318. Rect2 remove_rect = Rect2(remove_hpos, icon_start_height - remove->get_height() / 2.0, remove->get_width(), remove->get_height());
  319. if (read_only) {
  320. draw_texture(remove, remove_rect.position, dc);
  321. } else {
  322. draw_texture(remove, remove_rect.position);
  323. }
  324. Rect2 lock_rect = Rect2(lock_hpos, icon_start_height - lock->get_height() / 2.0, lock->get_width(), lock->get_height());
  325. if (locked_tracks.has(current_track)) {
  326. draw_texture(lock, lock_rect.position);
  327. } else {
  328. draw_texture(unlock, lock_rect.position);
  329. }
  330. Rect2 visible_rect = Rect2(visibility_hpos, icon_start_height - visibility_visible->get_height() / 2.0, visibility_visible->get_width(), visibility_visible->get_height());
  331. if (hidden_tracks.has(current_track)) {
  332. draw_texture(visibility_hidden, visible_rect.position);
  333. } else {
  334. draw_texture(visibility_visible, visible_rect.position);
  335. }
  336. Rect2 solo_rect = Rect2(solo_hpos, icon_start_height - solo->get_height() / 2.0, solo->get_width(), solo->get_height());
  337. draw_texture(solo, solo_rect.position);
  338. RBMap<int, Rect2> track_icons;
  339. track_icons[REMOVE_ICON] = remove_rect;
  340. track_icons[LOCK_ICON] = lock_rect;
  341. track_icons[VISIBILITY_ICON] = visible_rect;
  342. track_icons[SOLO_ICON] = solo_rect;
  343. subtrack_icons[current_track] = track_icons;
  344. vofs += text_buf.get_size().y + vsep;
  345. }
  346. }
  347. Color accent = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
  348. { //guides
  349. float min_left_scale = font->get_height(font_size) + vsep;
  350. float scale = (min_left_scale * 2) * v_zoom;
  351. float step = Math::pow(10.0, Math::round(Math::log(scale / 5.0) / Math::log(10.0))) * 5.0;
  352. scale = Math::snapped(scale, step);
  353. while (scale / v_zoom < min_left_scale * 2) {
  354. scale += step;
  355. }
  356. bool first = true;
  357. int prev_iv = 0;
  358. for (int i = font->get_height(font_size); i < get_size().height; i++) {
  359. float ofs = get_size().height / 2.0 - i;
  360. ofs *= v_zoom;
  361. ofs += v_scroll;
  362. int iv = int(ofs / scale);
  363. if (ofs < 0) {
  364. iv -= 1;
  365. }
  366. if (!first && iv != prev_iv) {
  367. Color lc = linecolor;
  368. lc.a *= 0.5;
  369. draw_line(Point2(limit, i), Point2(right_limit, i), lc, Math::round(EDSCALE));
  370. Color c = color;
  371. c.a *= 0.5;
  372. draw_string(font, Point2(limit + 8, i - 2), TS->format_number(rtos(Math::snapped((iv + 1) * scale, step))), HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, c);
  373. }
  374. first = false;
  375. prev_iv = iv;
  376. }
  377. }
  378. { //draw OTHER curves
  379. float scale = timeline->get_zoom_scale();
  380. Ref<Texture2D> point = get_theme_icon(SNAME("KeyValue"), SNAME("EditorIcons"));
  381. for (const KeyValue<int, Color> &E : subtrack_colors) {
  382. if (hidden_tracks.has(E.key)) {
  383. continue;
  384. }
  385. _draw_track(E.key, E.value);
  386. for (int i = 0; i < animation->track_get_key_count(E.key); i++) {
  387. float offset = animation->track_get_key_time(E.key, i);
  388. float value = animation->bezier_track_get_key_value(E.key, i);
  389. Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
  390. if (pos.x >= limit && pos.x <= right_limit) {
  391. draw_texture(point, pos - point->get_size() / 2.0, E.value);
  392. }
  393. }
  394. }
  395. if (track_count > 0 && !hidden_tracks.has(selected_track)) {
  396. //draw edited curve
  397. _draw_track(selected_track, selected_track_color);
  398. }
  399. }
  400. //draw editor handles
  401. {
  402. edit_points.clear();
  403. float scale = timeline->get_zoom_scale();
  404. for (int i = 0; i < track_count; ++i) {
  405. if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i)) {
  406. continue;
  407. }
  408. if (hidden_tracks.has(i) || locked_tracks.has(i)) {
  409. continue;
  410. }
  411. int key_count = animation->track_get_key_count(i);
  412. String path = animation->track_get_path(i);
  413. if (is_filtered) {
  414. if (root && root->has_node(path)) {
  415. Node *node = root->get_node(path);
  416. if (!node) {
  417. continue; // No node, no filter.
  418. }
  419. if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
  420. continue; // Skip track due to not selected.
  421. }
  422. }
  423. }
  424. for (int j = 0; j < key_count; ++j) {
  425. float offset = animation->track_get_key_time(i, j);
  426. float value = animation->bezier_track_get_key_value(i, j);
  427. if (moving_selection && selection.has(IntPair(i, j))) {
  428. offset += moving_selection_offset.x;
  429. value += moving_selection_offset.y;
  430. }
  431. Vector2 pos((offset - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value));
  432. Vector2 in_vec = animation->bezier_track_get_key_in_handle(i, j);
  433. if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
  434. in_vec = moving_handle_left;
  435. }
  436. Vector2 pos_in(((offset + in_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + in_vec.y));
  437. Vector2 out_vec = animation->bezier_track_get_key_out_handle(i, j);
  438. if ((moving_handle == 1 || moving_handle == -1) && moving_handle_track == i && moving_handle_key == j) {
  439. out_vec = moving_handle_right;
  440. }
  441. Vector2 pos_out(((offset + out_vec.x) - timeline->get_value()) * scale + limit, _bezier_h_to_pixel(value + out_vec.y));
  442. if (i == selected_track || selection.has(IntPair(i, j))) {
  443. _draw_line_clipped(pos, pos_in, accent, limit, right_limit);
  444. _draw_line_clipped(pos, pos_out, accent, limit, right_limit);
  445. }
  446. EditPoint ep;
  447. ep.track = i;
  448. ep.key = j;
  449. if (pos.x >= limit && pos.x <= right_limit) {
  450. ep.point_rect.position = (pos - bezier_icon->get_size() / 2.0).floor();
  451. ep.point_rect.size = bezier_icon->get_size();
  452. if (selection.has(IntPair(i, j))) {
  453. draw_texture(selected_icon, ep.point_rect.position);
  454. 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);
  455. 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);
  456. } else {
  457. Color track_color = Color(1, 1, 1, 1);
  458. if (i != selected_track) {
  459. track_color = subtrack_colors[i];
  460. }
  461. draw_texture(bezier_icon, ep.point_rect.position, track_color);
  462. }
  463. ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
  464. }
  465. ep.point_rect = ep.point_rect.grow(ep.point_rect.size.width * 0.5);
  466. if (i == selected_track || selection.has(IntPair(i, j))) {
  467. if (animation->bezier_track_get_key_handle_mode(i, j) != Animation::HANDLE_MODE_LINEAR) {
  468. if (pos_in.x >= limit && pos_in.x <= right_limit) {
  469. ep.in_rect.position = (pos_in - bezier_handle_icon->get_size() / 2.0).floor();
  470. ep.in_rect.size = bezier_handle_icon->get_size();
  471. draw_texture(bezier_handle_icon, ep.in_rect.position);
  472. ep.in_rect = ep.in_rect.grow(ep.in_rect.size.width * 0.5);
  473. }
  474. if (pos_out.x >= limit && pos_out.x <= right_limit) {
  475. ep.out_rect.position = (pos_out - bezier_handle_icon->get_size() / 2.0).floor();
  476. ep.out_rect.size = bezier_handle_icon->get_size();
  477. draw_texture(bezier_handle_icon, ep.out_rect.position);
  478. ep.out_rect = ep.out_rect.grow(ep.out_rect.size.width * 0.5);
  479. }
  480. }
  481. }
  482. if (!locked_tracks.has(i)) {
  483. edit_points.push_back(ep);
  484. }
  485. }
  486. }
  487. for (int i = 0; i < edit_points.size(); ++i) {
  488. if (edit_points[i].track == selected_track) {
  489. EditPoint ep = edit_points[i];
  490. edit_points.remove_at(i);
  491. edit_points.insert(0, ep);
  492. }
  493. }
  494. }
  495. if (box_selecting) {
  496. Vector2 bs_from = box_selection_from;
  497. Vector2 bs_to = box_selection_to;
  498. if (bs_from.x > bs_to.x) {
  499. SWAP(bs_from.x, bs_to.x);
  500. }
  501. if (bs_from.y > bs_to.y) {
  502. SWAP(bs_from.y, bs_to.y);
  503. }
  504. draw_rect(
  505. Rect2(bs_from, bs_to - bs_from),
  506. get_theme_color(SNAME("box_selection_fill_color"), SNAME("Editor")));
  507. draw_rect(
  508. Rect2(bs_from, bs_to - bs_from),
  509. get_theme_color(SNAME("box_selection_stroke_color"), SNAME("Editor")),
  510. false,
  511. Math::round(EDSCALE));
  512. }
  513. } break;
  514. }
  515. }
  516. Ref<Animation> AnimationBezierTrackEdit::get_animation() const {
  517. return animation;
  518. }
  519. void AnimationBezierTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track, bool p_read_only) {
  520. animation = p_animation;
  521. read_only = p_read_only;
  522. selected_track = p_track;
  523. queue_redraw();
  524. }
  525. Size2 AnimationBezierTrackEdit::get_minimum_size() const {
  526. return Vector2(1, 1);
  527. }
  528. void AnimationBezierTrackEdit::set_undo_redo(Ref<EditorUndoRedoManager> p_undo_redo) {
  529. undo_redo = p_undo_redo;
  530. }
  531. void AnimationBezierTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
  532. timeline = p_timeline;
  533. timeline->connect("zoom_changed", callable_mp(this, &AnimationBezierTrackEdit::_zoom_changed));
  534. timeline->connect("name_limit_changed", callable_mp(this, &AnimationBezierTrackEdit::_zoom_changed));
  535. }
  536. void AnimationBezierTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
  537. editor = p_editor;
  538. connect("clear_selection", callable_mp(editor, &AnimationTrackEditor::_clear_selection).bind(false));
  539. connect("select_key", callable_mp(editor, &AnimationTrackEditor::_key_selected), CONNECT_DEFERRED);
  540. }
  541. void AnimationBezierTrackEdit::_play_position_draw() {
  542. if (!animation.is_valid() || play_position_pos < 0) {
  543. return;
  544. }
  545. float scale = timeline->get_zoom_scale();
  546. int h = get_size().height;
  547. int limit = timeline->get_name_limit();
  548. int px = (-timeline->get_value() + play_position_pos) * scale + limit;
  549. if (px >= limit && px < (get_size().width)) {
  550. Color color = get_theme_color(SNAME("accent_color"), SNAME("Editor"));
  551. play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE));
  552. }
  553. }
  554. void AnimationBezierTrackEdit::set_play_position(real_t p_pos) {
  555. play_position_pos = p_pos;
  556. play_position->queue_redraw();
  557. }
  558. void AnimationBezierTrackEdit::update_play_position() {
  559. play_position->queue_redraw();
  560. }
  561. void AnimationBezierTrackEdit::set_root(Node *p_root) {
  562. root = p_root;
  563. }
  564. void AnimationBezierTrackEdit::set_filtered(bool p_filtered) {
  565. is_filtered = p_filtered;
  566. if (animation == nullptr) {
  567. return;
  568. }
  569. String base_path = animation->track_get_path(selected_track);
  570. if (is_filtered) {
  571. if (root && root->has_node(base_path)) {
  572. Node *node = root->get_node(base_path);
  573. if (!node || !EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
  574. for (int i = 0; i < animation->get_track_count(); ++i) {
  575. if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER) {
  576. continue;
  577. }
  578. base_path = animation->track_get_path(i);
  579. if (root && root->has_node(base_path)) {
  580. node = root->get_node(base_path);
  581. if (!node) {
  582. continue; // No node, no filter.
  583. }
  584. if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
  585. continue; // Skip track due to not selected.
  586. }
  587. set_animation_and_track(animation, i, read_only);
  588. break;
  589. }
  590. }
  591. }
  592. }
  593. }
  594. queue_redraw();
  595. }
  596. void AnimationBezierTrackEdit::_zoom_changed() {
  597. queue_redraw();
  598. play_position->queue_redraw();
  599. }
  600. void AnimationBezierTrackEdit::_update_locked_tracks_after(int p_track) {
  601. if (locked_tracks.has(p_track)) {
  602. locked_tracks.erase(p_track);
  603. }
  604. Vector<int> updated_locked_tracks;
  605. for (const int &E : locked_tracks) {
  606. updated_locked_tracks.push_back(E);
  607. }
  608. locked_tracks.clear();
  609. for (int i = 0; i < updated_locked_tracks.size(); ++i) {
  610. if (updated_locked_tracks[i] > p_track) {
  611. locked_tracks.insert(updated_locked_tracks[i] - 1);
  612. } else {
  613. locked_tracks.insert(updated_locked_tracks[i]);
  614. }
  615. }
  616. }
  617. void AnimationBezierTrackEdit::_update_hidden_tracks_after(int p_track) {
  618. if (hidden_tracks.has(p_track)) {
  619. hidden_tracks.erase(p_track);
  620. }
  621. Vector<int> updated_hidden_tracks;
  622. for (const int &E : hidden_tracks) {
  623. updated_hidden_tracks.push_back(E);
  624. }
  625. hidden_tracks.clear();
  626. for (int i = 0; i < updated_hidden_tracks.size(); ++i) {
  627. if (updated_hidden_tracks[i] > p_track) {
  628. hidden_tracks.insert(updated_hidden_tracks[i] - 1);
  629. } else {
  630. hidden_tracks.insert(updated_hidden_tracks[i]);
  631. }
  632. }
  633. }
  634. String AnimationBezierTrackEdit::get_tooltip(const Point2 &p_pos) const {
  635. return Control::get_tooltip(p_pos);
  636. }
  637. void AnimationBezierTrackEdit::_clear_selection() {
  638. selection.clear();
  639. emit_signal(SNAME("clear_selection"));
  640. queue_redraw();
  641. }
  642. void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) {
  643. undo_redo->create_action(TTR("Update Selected Key Handles"));
  644. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  645. const IntPair track_key_pair = E->get();
  646. undo_redo->add_undo_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_handle_mode(track_key_pair.first, track_key_pair.second), Animation::HANDLE_SET_MODE_NONE);
  647. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_in_handle(track_key_pair.first, track_key_pair.second));
  648. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track_key_pair.first, track_key_pair.second, animation->bezier_track_get_key_out_handle(track_key_pair.first, track_key_pair.second));
  649. undo_redo->add_do_method(editor, "_bezier_track_set_key_handle_mode", animation.ptr(), track_key_pair.first, track_key_pair.second, p_mode, p_auto ? Animation::HANDLE_SET_MODE_AUTO : Animation::HANDLE_SET_MODE_RESET);
  650. }
  651. undo_redo->commit_action();
  652. }
  653. void AnimationBezierTrackEdit::_clear_selection_for_anim(const Ref<Animation> &p_anim) {
  654. if (!(animation == p_anim)) {
  655. return;
  656. }
  657. _clear_selection();
  658. }
  659. void AnimationBezierTrackEdit::_select_at_anim(const Ref<Animation> &p_anim, int p_track, real_t p_pos) {
  660. if (!(animation == p_anim)) {
  661. return;
  662. }
  663. int idx = animation->track_find_key(p_track, p_pos, true);
  664. ERR_FAIL_COND(idx < 0);
  665. selection.insert(IntPair(p_track, idx));
  666. emit_signal(SNAME("select_key"), idx, true, p_track);
  667. queue_redraw();
  668. }
  669. void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
  670. ERR_FAIL_COND(p_event.is_null());
  671. if (panner->gui_input(p_event)) {
  672. accept_event();
  673. return;
  674. }
  675. if (p_event->is_pressed()) {
  676. if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->matches_event(p_event)) {
  677. if (!read_only) {
  678. duplicate_selection();
  679. }
  680. accept_event();
  681. }
  682. if (ED_GET_SHORTCUT("animation_editor/delete_selection")->matches_event(p_event)) {
  683. if (!read_only) {
  684. delete_selection();
  685. }
  686. accept_event();
  687. }
  688. }
  689. Ref<InputEventKey> key_press = p_event;
  690. if (key_press.is_valid() && key_press->is_pressed()) {
  691. if (ED_GET_SHORTCUT("animation_bezier_editor/focus")->matches_event(p_event)) {
  692. SelectionSet focused_keys;
  693. if (selection.is_empty()) {
  694. for (int i = 0; i < edit_points.size(); ++i) {
  695. IntPair key_pair = IntPair(edit_points[i].track, edit_points[i].key);
  696. focused_keys.insert(key_pair);
  697. }
  698. } else {
  699. for (const IntPair &E : selection) {
  700. focused_keys.insert(E);
  701. if (E.second > 0) {
  702. IntPair previous_key = IntPair(E.first, E.second - 1);
  703. focused_keys.insert(previous_key);
  704. }
  705. if (E.second < animation->track_get_key_count(E.first) - 1) {
  706. IntPair next_key = IntPair(E.first, E.second + 1);
  707. focused_keys.insert(next_key);
  708. }
  709. }
  710. }
  711. if (focused_keys.is_empty()) {
  712. accept_event();
  713. return;
  714. }
  715. real_t minimum_time = INFINITY;
  716. real_t maximum_time = -INFINITY;
  717. real_t minimum_value = INFINITY;
  718. real_t maximum_value = -INFINITY;
  719. for (const IntPair &E : selection) {
  720. IntPair key_pair = E;
  721. real_t time = animation->track_get_key_time(key_pair.first, key_pair.second);
  722. real_t value = animation->bezier_track_get_key_value(key_pair.first, key_pair.second);
  723. minimum_time = MIN(time, minimum_time);
  724. maximum_time = MAX(time, maximum_time);
  725. minimum_value = MIN(value, minimum_value);
  726. maximum_value = MAX(value, maximum_value);
  727. }
  728. float width = get_size().width - timeline->get_name_limit() - timeline->get_buttons_width();
  729. float padding = width * 0.1;
  730. float desired_scale = (width - padding / 2.0) / (maximum_time - minimum_time);
  731. minimum_time = MAX(0, minimum_time - (padding / 2.0) / desired_scale);
  732. float zv = Math::pow(100 / desired_scale, 0.125f);
  733. if (zv < 1) {
  734. zv = Math::pow(desired_scale / 100, 0.125f) - 1;
  735. zv = 1 - zv;
  736. }
  737. float zoom_value = timeline->get_zoom()->get_max() - zv;
  738. timeline->get_zoom()->set_value(zoom_value);
  739. timeline->call_deferred("set_value", minimum_time);
  740. v_scroll = (maximum_value + minimum_value) / 2.0;
  741. v_zoom = (maximum_value - minimum_value) / ((get_size().height - timeline->get_size().height) * 0.9);
  742. queue_redraw();
  743. accept_event();
  744. return;
  745. } else if (ED_GET_SHORTCUT("animation_bezier_editor/select_all_keys")->matches_event(p_event)) {
  746. for (int i = 0; i < edit_points.size(); ++i) {
  747. selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
  748. }
  749. queue_redraw();
  750. accept_event();
  751. return;
  752. } else if (ED_GET_SHORTCUT("animation_bezier_editor/deselect_all_keys")->matches_event(p_event)) {
  753. selection.clear();
  754. queue_redraw();
  755. accept_event();
  756. return;
  757. }
  758. }
  759. Ref<InputEventMouseButton> mb = p_event;
  760. int limit = timeline->get_name_limit();
  761. if (mb.is_valid() && mb->get_button_index() == MouseButton::RIGHT && mb->is_pressed()) {
  762. menu_insert_key = mb->get_position();
  763. if (menu_insert_key.x >= limit && menu_insert_key.x <= get_size().width) {
  764. if (!read_only) {
  765. Vector2 popup_pos = get_screen_position() + mb->get_position();
  766. menu->clear();
  767. if (!locked_tracks.has(selected_track) || locked_tracks.has(selected_track)) {
  768. menu->add_icon_item(bezier_icon, TTR("Insert Key Here"), MENU_KEY_INSERT);
  769. }
  770. if (selection.size()) {
  771. menu->add_separator();
  772. menu->add_icon_item(get_theme_icon(SNAME("Duplicate"), SNAME("EditorIcons")), TTR("Duplicate Selected Key(s)"), MENU_KEY_DUPLICATE);
  773. menu->add_separator();
  774. menu->add_icon_item(get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")), TTR("Delete Selected Key(s)"), MENU_KEY_DELETE);
  775. menu->add_separator();
  776. menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesFree"), SNAME("EditorIcons")), TTR("Make Handles Free"), MENU_KEY_SET_HANDLE_FREE);
  777. menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesLinear"), SNAME("EditorIcons")), TTR("Make Handles Linear"), MENU_KEY_SET_HANDLE_LINEAR);
  778. menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced"), MENU_KEY_SET_HANDLE_BALANCED);
  779. menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored"), MENU_KEY_SET_HANDLE_MIRRORED);
  780. menu->add_separator();
  781. menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesBalanced"), SNAME("EditorIcons")), TTR("Make Handles Balanced (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_BALANCED);
  782. menu->add_icon_item(get_theme_icon(SNAME("BezierHandlesMirror"), SNAME("EditorIcons")), TTR("Make Handles Mirrored (Auto Tangent)"), MENU_KEY_SET_HANDLE_AUTO_MIRRORED);
  783. }
  784. if (menu->get_item_count()) {
  785. menu->reset_size();
  786. menu->set_position(popup_pos);
  787. menu->popup();
  788. }
  789. }
  790. }
  791. }
  792. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  793. for (const KeyValue<int, Rect2> &E : subtracks) {
  794. if (E.value.has_point(mb->get_position())) {
  795. if (!locked_tracks.has(E.key) && !hidden_tracks.has(E.key)) {
  796. set_animation_and_track(animation, E.key, read_only);
  797. _clear_selection();
  798. }
  799. return;
  800. }
  801. }
  802. for (const KeyValue<int, RBMap<int, Rect2>> &E : subtrack_icons) {
  803. int track = E.key;
  804. RBMap<int, Rect2> track_icons = E.value;
  805. for (const KeyValue<int, Rect2> &I : track_icons) {
  806. if (I.value.has_point(mb->get_position())) {
  807. if (I.key == REMOVE_ICON) {
  808. if (!read_only) {
  809. undo_redo->create_action("Remove Bezier Track");
  810. undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
  811. undo_redo->add_do_method(this, "_update_hidden_tracks_after", track);
  812. undo_redo->add_do_method(animation.ptr(), "remove_track", track);
  813. undo_redo->add_undo_method(animation.ptr(), "add_track", Animation::TrackType::TYPE_BEZIER, track);
  814. undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
  815. for (int i = 0; i < animation->track_get_key_count(track); ++i) {
  816. undo_redo->add_undo_method(
  817. this,
  818. "_bezier_track_insert_key",
  819. track,
  820. animation->track_get_key_time(track, i),
  821. animation->bezier_track_get_key_value(track, i),
  822. animation->bezier_track_get_key_in_handle(track, i),
  823. animation->bezier_track_get_key_out_handle(track, i),
  824. animation->bezier_track_get_key_handle_mode(track, i));
  825. }
  826. undo_redo->commit_action();
  827. selected_track = CLAMP(selected_track, 0, animation->get_track_count() - 1);
  828. }
  829. return;
  830. } else if (I.key == LOCK_ICON) {
  831. if (locked_tracks.has(track)) {
  832. locked_tracks.erase(track);
  833. } else {
  834. locked_tracks.insert(track);
  835. if (selected_track == track) {
  836. for (int i = 0; i < animation->get_track_count(); ++i) {
  837. if (!locked_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
  838. set_animation_and_track(animation, i, read_only);
  839. break;
  840. }
  841. }
  842. }
  843. }
  844. queue_redraw();
  845. return;
  846. } else if (I.key == VISIBILITY_ICON) {
  847. if (hidden_tracks.has(track)) {
  848. hidden_tracks.erase(track);
  849. } else {
  850. hidden_tracks.insert(track);
  851. if (selected_track == track) {
  852. for (int i = 0; i < animation->get_track_count(); ++i) {
  853. if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
  854. set_animation_and_track(animation, i, read_only);
  855. break;
  856. }
  857. }
  858. }
  859. }
  860. Vector<int> visible_tracks;
  861. for (int i = 0; i < animation->get_track_count(); ++i) {
  862. if (!hidden_tracks.has(i) && animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
  863. visible_tracks.push_back(i);
  864. }
  865. }
  866. if (visible_tracks.size() == 1) {
  867. solo_track = visible_tracks[0];
  868. } else {
  869. solo_track = -1;
  870. }
  871. queue_redraw();
  872. return;
  873. } else if (I.key == SOLO_ICON) {
  874. if (solo_track == track) {
  875. solo_track = -1;
  876. hidden_tracks.clear();
  877. } else {
  878. if (hidden_tracks.has(track)) {
  879. hidden_tracks.erase(track);
  880. }
  881. for (int i = 0; i < animation->get_track_count(); ++i) {
  882. if (animation->track_get_type(i) == Animation::TrackType::TYPE_BEZIER) {
  883. if (i != track && !hidden_tracks.has(i)) {
  884. hidden_tracks.insert(i);
  885. }
  886. }
  887. }
  888. set_animation_and_track(animation, track, read_only);
  889. solo_track = track;
  890. }
  891. queue_redraw();
  892. return;
  893. }
  894. return;
  895. }
  896. }
  897. }
  898. for (int i = 0; i < edit_points.size(); i++) {
  899. //first check point
  900. //command makes it ignore the main point, so control point editors can be force-edited
  901. //path 2D editing in the 3D and 2D editors works the same way
  902. if (!mb->is_command_or_control_pressed()) {
  903. if (edit_points[i].point_rect.has_point(mb->get_position())) {
  904. IntPair pair = IntPair(edit_points[i].track, edit_points[i].key);
  905. if (mb->is_shift_pressed()) {
  906. //add to selection
  907. if (selection.has(pair)) {
  908. selection.erase(pair);
  909. } else {
  910. selection.insert(pair);
  911. }
  912. queue_redraw();
  913. select_single_attempt = IntPair(-1, -1);
  914. } else if (selection.has(pair)) {
  915. moving_selection_attempt = true;
  916. moving_selection = false;
  917. moving_selection_from_key = pair.second;
  918. moving_selection_from_track = pair.first;
  919. moving_handle_track = pair.first;
  920. moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
  921. moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);
  922. moving_selection_offset = Vector2();
  923. select_single_attempt = pair;
  924. queue_redraw();
  925. } else {
  926. moving_selection_attempt = true;
  927. moving_selection = true;
  928. moving_selection_from_key = pair.second;
  929. moving_selection_from_track = pair.first;
  930. moving_selection_offset = Vector2();
  931. moving_handle_track = pair.first;
  932. moving_handle_left = animation->bezier_track_get_key_in_handle(pair.first, pair.second);
  933. moving_handle_right = animation->bezier_track_get_key_out_handle(pair.first, pair.second);
  934. selection.clear();
  935. selection.insert(pair);
  936. set_animation_and_track(animation, pair.first, read_only);
  937. }
  938. return;
  939. }
  940. }
  941. if (!read_only) {
  942. if (edit_points[i].in_rect.has_point(mb->get_position())) {
  943. moving_handle = -1;
  944. moving_handle_key = edit_points[i].key;
  945. moving_handle_track = edit_points[i].track;
  946. moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
  947. moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
  948. queue_redraw();
  949. return;
  950. }
  951. if (edit_points[i].out_rect.has_point(mb->get_position())) {
  952. moving_handle = 1;
  953. moving_handle_key = edit_points[i].key;
  954. moving_handle_track = edit_points[i].track;
  955. moving_handle_left = animation->bezier_track_get_key_in_handle(edit_points[i].track, edit_points[i].key);
  956. moving_handle_right = animation->bezier_track_get_key_out_handle(edit_points[i].track, edit_points[i].key);
  957. queue_redraw();
  958. return;
  959. }
  960. }
  961. }
  962. //insert new point
  963. if (mb->get_position().x >= limit && mb->get_position().x < get_size().width && mb->is_command_or_control_pressed()) {
  964. Array new_point;
  965. new_point.resize(5);
  966. float h = (get_size().height / 2.0 - mb->get_position().y) * v_zoom + v_scroll;
  967. new_point[0] = h;
  968. new_point[1] = -0.25;
  969. new_point[2] = 0;
  970. new_point[3] = 0.25;
  971. new_point[4] = 0;
  972. real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
  973. while (animation->track_find_key(selected_track, time, true) != -1) {
  974. time += 0.001;
  975. }
  976. undo_redo->create_action(TTR("Add Bezier Point"));
  977. undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point);
  978. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
  979. undo_redo->commit_action();
  980. //then attempt to move
  981. int index = animation->track_find_key(selected_track, time, true);
  982. ERR_FAIL_COND(index == -1);
  983. _clear_selection();
  984. selection.insert(IntPair(selected_track, index));
  985. moving_selection_attempt = true;
  986. moving_selection = false;
  987. moving_selection_from_key = index;
  988. moving_selection_from_track = selected_track;
  989. moving_selection_offset = Vector2();
  990. select_single_attempt = IntPair(-1, -1);
  991. queue_redraw();
  992. return;
  993. }
  994. //box select
  995. if (mb->get_position().x >= limit && mb->get_position().x < get_size().width) {
  996. box_selecting_attempt = true;
  997. box_selecting = false;
  998. box_selecting_add = false;
  999. box_selection_from = mb->get_position();
  1000. return;
  1001. }
  1002. }
  1003. if (box_selecting_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  1004. if (box_selecting) {
  1005. //do actual select
  1006. if (!box_selecting_add) {
  1007. _clear_selection();
  1008. }
  1009. Vector2 bs_from = box_selection_from;
  1010. Vector2 bs_to = box_selection_to;
  1011. if (bs_from.x > bs_to.x) {
  1012. SWAP(bs_from.x, bs_to.x);
  1013. }
  1014. if (bs_from.y > bs_to.y) {
  1015. SWAP(bs_from.y, bs_to.y);
  1016. }
  1017. Rect2 selection_rect(bs_from, bs_to - bs_from);
  1018. bool track_set = false;
  1019. for (int i = 0; i < edit_points.size(); i++) {
  1020. if (edit_points[i].point_rect.intersects(selection_rect)) {
  1021. selection.insert(IntPair(edit_points[i].track, edit_points[i].key));
  1022. if (!track_set) {
  1023. track_set = true;
  1024. set_animation_and_track(animation, edit_points[i].track, read_only);
  1025. }
  1026. }
  1027. }
  1028. } else {
  1029. _clear_selection(); //clicked and nothing happened, so clear the selection
  1030. //select by clicking on curve
  1031. int track_count = animation->get_track_count();
  1032. real_t animation_length = animation->get_length();
  1033. animation->set_length(real_t(INT_MAX)); //bezier_track_interpolate doesn't find keys if they exist beyond anim length
  1034. real_t time = ((mb->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
  1035. for (int i = 0; i < track_count; ++i) {
  1036. if (animation->track_get_type(i) != Animation::TrackType::TYPE_BEZIER || hidden_tracks.has(i) || locked_tracks.has(i)) {
  1037. continue;
  1038. }
  1039. float track_h = animation->bezier_track_interpolate(i, time);
  1040. float track_height = _bezier_h_to_pixel(track_h);
  1041. if (abs(mb->get_position().y - track_height) < 10) {
  1042. set_animation_and_track(animation, i, read_only);
  1043. break;
  1044. }
  1045. }
  1046. animation->set_length(animation_length);
  1047. }
  1048. box_selecting_attempt = false;
  1049. box_selecting = false;
  1050. queue_redraw();
  1051. }
  1052. if (moving_selection_attempt && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  1053. if (!read_only) {
  1054. if (moving_selection) {
  1055. //combit it
  1056. undo_redo->create_action(TTR("Move Bezier Points"));
  1057. List<AnimMoveRestore> to_restore;
  1058. List<Animation::HandleMode> to_restore_handle_modes;
  1059. // 1-remove the keys
  1060. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1061. undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
  1062. }
  1063. // 2- remove overlapped keys
  1064. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1065. real_t newtime = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
  1066. int idx = animation->track_find_key(E->get().first, newtime, true);
  1067. if (idx == -1) {
  1068. continue;
  1069. }
  1070. if (selection.has(IntPair(E->get().first, idx))) {
  1071. continue; //already in selection, don't save
  1072. }
  1073. undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newtime);
  1074. AnimMoveRestore amr;
  1075. amr.key = animation->track_get_key_value(E->get().first, idx);
  1076. amr.track = E->get().first;
  1077. amr.time = newtime;
  1078. to_restore.push_back(amr);
  1079. to_restore_handle_modes.push_back(animation->bezier_track_get_key_handle_mode(E->get().first, idx));
  1080. }
  1081. // 3-move the keys (re insert them)
  1082. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1083. real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
  1084. Array key = animation->track_get_key_value(E->get().first, E->get().second);
  1085. real_t h = key[0];
  1086. h += moving_selection_offset.y;
  1087. key[0] = h;
  1088. undo_redo->add_do_method(
  1089. this,
  1090. "_bezier_track_insert_key",
  1091. E->get().first,
  1092. newpos,
  1093. key[0],
  1094. Vector2(key[1], key[2]),
  1095. Vector2(key[3], key[4]),
  1096. animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
  1097. }
  1098. // 4-(undo) remove inserted keys
  1099. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1100. real_t newpos = editor->snap_time(animation->track_get_key_time(E->get().first, E->get().second) + moving_selection_offset.x);
  1101. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, newpos);
  1102. }
  1103. // 5-(undo) reinsert keys
  1104. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1105. real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
  1106. Array key = animation->track_get_key_value(E->get().first, E->get().second);
  1107. undo_redo->add_undo_method(
  1108. this,
  1109. "_bezier_track_insert_key",
  1110. E->get().first,
  1111. oldpos,
  1112. key[0],
  1113. Vector2(key[1], key[2]),
  1114. Vector2(key[3], key[4]),
  1115. animation->bezier_track_get_key_handle_mode(E->get().first, E->get().second));
  1116. }
  1117. // 6-(undo) reinsert overlapped keys
  1118. for (int i = 0; i < to_restore.size(); i++) {
  1119. const AnimMoveRestore &amr = to_restore[i];
  1120. Array key = amr.key;
  1121. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, 1);
  1122. undo_redo->add_undo_method(
  1123. this,
  1124. "_bezier_track_insert_key",
  1125. amr.track,
  1126. amr.time,
  1127. key[0],
  1128. Vector2(key[1], key[2]),
  1129. Vector2(key[3], key[4]),
  1130. to_restore_handle_modes[i]);
  1131. }
  1132. undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
  1133. undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
  1134. // 7-reselect
  1135. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1136. real_t oldpos = animation->track_get_key_time(E->get().first, E->get().second);
  1137. real_t newpos = editor->snap_time(oldpos + moving_selection_offset.x);
  1138. undo_redo->add_do_method(this, "_select_at_anim", animation, E->get().first, newpos);
  1139. undo_redo->add_undo_method(this, "_select_at_anim", animation, E->get().first, oldpos);
  1140. }
  1141. undo_redo->commit_action();
  1142. moving_selection = false;
  1143. } else if (select_single_attempt != IntPair(-1, -1)) {
  1144. selection.clear();
  1145. selection.insert(select_single_attempt);
  1146. set_animation_and_track(animation, select_single_attempt.first, read_only);
  1147. }
  1148. moving_selection_attempt = false;
  1149. queue_redraw();
  1150. }
  1151. }
  1152. Ref<InputEventMouseMotion> mm = p_event;
  1153. if (moving_selection_attempt && mm.is_valid()) {
  1154. if (!moving_selection) {
  1155. moving_selection = true;
  1156. select_single_attempt = IntPair(-1, -1);
  1157. }
  1158. float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll;
  1159. float x = editor->snap_time(((mm->get_position().x - limit) / timeline->get_zoom_scale()) + timeline->get_value());
  1160. if (!read_only) {
  1161. moving_selection_offset = Vector2(x - animation->track_get_key_time(moving_selection_from_track, moving_selection_from_key), y - animation->bezier_track_get_key_value(moving_selection_from_track, moving_selection_from_key));
  1162. }
  1163. additional_moving_handle_lefts.clear();
  1164. additional_moving_handle_rights.clear();
  1165. queue_redraw();
  1166. }
  1167. if (box_selecting_attempt && mm.is_valid()) {
  1168. if (!box_selecting) {
  1169. box_selecting = true;
  1170. box_selecting_add = mm->is_shift_pressed();
  1171. }
  1172. box_selection_to = mm->get_position();
  1173. if (get_local_mouse_position().y < 0) {
  1174. //avoid cursor from going too above, so it does not lose focus with viewport
  1175. warp_mouse(Vector2(get_local_mouse_position().x, 0));
  1176. }
  1177. queue_redraw();
  1178. }
  1179. if ((moving_handle == 1 || moving_handle == -1) && mm.is_valid()) {
  1180. float y = (get_size().height / 2.0 - mm->get_position().y) * v_zoom + v_scroll;
  1181. float x = editor->snap_time((mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale()) + timeline->get_value();
  1182. Vector2 key_pos = Vector2(animation->track_get_key_time(selected_track, moving_handle_key), animation->bezier_track_get_key_value(selected_track, moving_handle_key));
  1183. Vector2 moving_handle_value = Vector2(x, y) - key_pos;
  1184. moving_handle_left = animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key);
  1185. moving_handle_right = animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key);
  1186. if (moving_handle == -1) {
  1187. moving_handle_left = moving_handle_value;
  1188. Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key);
  1189. if (handle_mode == Animation::HANDLE_MODE_BALANCED) {
  1190. real_t ratio = timeline->get_zoom_scale() * v_zoom;
  1191. Transform2D xform;
  1192. xform.set_scale(Vector2(1.0, 1.0 / ratio));
  1193. Vector2 vec_out = xform.xform(moving_handle_right);
  1194. Vector2 vec_in = xform.xform(moving_handle_left);
  1195. moving_handle_right = xform.affine_inverse().xform(-vec_in.normalized() * vec_out.length());
  1196. } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) {
  1197. moving_handle_right = -moving_handle_left;
  1198. }
  1199. } else if (moving_handle == 1) {
  1200. moving_handle_right = moving_handle_value;
  1201. Animation::HandleMode handle_mode = animation->bezier_track_get_key_handle_mode(moving_handle_track, moving_handle_key);
  1202. if (handle_mode == Animation::HANDLE_MODE_BALANCED) {
  1203. real_t ratio = timeline->get_zoom_scale() * v_zoom;
  1204. Transform2D xform;
  1205. xform.set_scale(Vector2(1.0, 1.0 / ratio));
  1206. Vector2 vec_in = xform.xform(moving_handle_left);
  1207. Vector2 vec_out = xform.xform(moving_handle_right);
  1208. moving_handle_left = xform.affine_inverse().xform(-vec_out.normalized() * vec_in.length());
  1209. } else if (handle_mode == Animation::HANDLE_MODE_MIRRORED) {
  1210. moving_handle_left = -moving_handle_right;
  1211. }
  1212. }
  1213. queue_redraw();
  1214. }
  1215. if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
  1216. if (!read_only) {
  1217. undo_redo->create_action(TTR("Move Bezier Points"));
  1218. if (moving_handle == -1) {
  1219. real_t ratio = timeline->get_zoom_scale() * v_zoom;
  1220. undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, moving_handle_left, ratio);
  1221. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_in_handle(moving_handle_track, moving_handle_key), ratio);
  1222. } else if (moving_handle == 1) {
  1223. real_t ratio = timeline->get_zoom_scale() * v_zoom;
  1224. undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, moving_handle_right, ratio);
  1225. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", moving_handle_track, moving_handle_key, animation->bezier_track_get_key_out_handle(moving_handle_track, moving_handle_key), ratio);
  1226. }
  1227. undo_redo->commit_action();
  1228. moving_handle = 0;
  1229. queue_redraw();
  1230. }
  1231. }
  1232. }
  1233. void AnimationBezierTrackEdit::_scroll_callback(Vector2 p_scroll_vec, bool p_alt) {
  1234. _pan_callback(-p_scroll_vec * 32);
  1235. }
  1236. void AnimationBezierTrackEdit::_pan_callback(Vector2 p_scroll_vec) {
  1237. v_scroll += p_scroll_vec.y * v_zoom;
  1238. v_scroll = CLAMP(v_scroll, -100000, 100000);
  1239. timeline->set_value(timeline->get_value() - p_scroll_vec.x / timeline->get_zoom_scale());
  1240. queue_redraw();
  1241. }
  1242. void AnimationBezierTrackEdit::_zoom_callback(Vector2 p_scroll_vec, Vector2 p_origin, bool p_alt) {
  1243. const float v_zoom_orig = v_zoom;
  1244. if (p_alt) {
  1245. // Alternate zoom (doesn't affect timeline).
  1246. if (p_scroll_vec.y > 0) {
  1247. v_zoom = MIN(v_zoom * 1.2, 100000);
  1248. } else {
  1249. v_zoom = MAX(v_zoom / 1.2, 0.000001);
  1250. }
  1251. } else {
  1252. if (p_scroll_vec.y > 0) {
  1253. timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
  1254. } else {
  1255. timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
  1256. }
  1257. }
  1258. v_scroll = v_scroll + (p_origin.y - get_size().y / 2.0) * (v_zoom - v_zoom_orig);
  1259. queue_redraw();
  1260. }
  1261. void AnimationBezierTrackEdit::_menu_selected(int p_index) {
  1262. switch (p_index) {
  1263. case MENU_KEY_INSERT: {
  1264. if (animation->get_track_count() > 0) {
  1265. Array new_point;
  1266. new_point.resize(5);
  1267. float h = (get_size().height / 2.0 - menu_insert_key.y) * v_zoom + v_scroll;
  1268. new_point[0] = h;
  1269. new_point[1] = -0.25;
  1270. new_point[2] = 0;
  1271. new_point[3] = 0.25;
  1272. new_point[4] = 0;
  1273. int limit = timeline->get_name_limit();
  1274. real_t time = ((menu_insert_key.x - limit) / timeline->get_zoom_scale()) + timeline->get_value();
  1275. while (animation->track_find_key(selected_track, time, true) != -1) {
  1276. time += 0.001;
  1277. }
  1278. undo_redo->create_action(TTR("Add Bezier Point"));
  1279. undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
  1280. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
  1281. undo_redo->commit_action();
  1282. queue_redraw();
  1283. }
  1284. } break;
  1285. case MENU_KEY_DUPLICATE: {
  1286. duplicate_selection();
  1287. } break;
  1288. case MENU_KEY_DELETE: {
  1289. delete_selection();
  1290. } break;
  1291. case MENU_KEY_SET_HANDLE_FREE: {
  1292. _change_selected_keys_handle_mode(Animation::HANDLE_MODE_FREE);
  1293. } break;
  1294. case MENU_KEY_SET_HANDLE_LINEAR: {
  1295. _change_selected_keys_handle_mode(Animation::HANDLE_MODE_LINEAR);
  1296. } break;
  1297. case MENU_KEY_SET_HANDLE_BALANCED: {
  1298. _change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED);
  1299. } break;
  1300. case MENU_KEY_SET_HANDLE_MIRRORED: {
  1301. _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED);
  1302. } break;
  1303. case MENU_KEY_SET_HANDLE_AUTO_BALANCED: {
  1304. _change_selected_keys_handle_mode(Animation::HANDLE_MODE_BALANCED, true);
  1305. } break;
  1306. case MENU_KEY_SET_HANDLE_AUTO_MIRRORED: {
  1307. _change_selected_keys_handle_mode(Animation::HANDLE_MODE_MIRRORED, true);
  1308. } break;
  1309. }
  1310. }
  1311. void AnimationBezierTrackEdit::duplicate_selection() {
  1312. if (selection.size() == 0) {
  1313. return;
  1314. }
  1315. real_t top_time = 1e10;
  1316. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1317. real_t t = animation->track_get_key_time(E->get().first, E->get().second);
  1318. if (t < top_time) {
  1319. top_time = t;
  1320. }
  1321. }
  1322. undo_redo->create_action(TTR("Anim Duplicate Keys"));
  1323. List<Pair<int, real_t>> new_selection_values;
  1324. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1325. real_t t = animation->track_get_key_time(E->get().first, E->get().second);
  1326. real_t dst_time = t + (timeline->get_play_position() - top_time);
  1327. int existing_idx = animation->track_find_key(E->get().first, dst_time, true);
  1328. 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));
  1329. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", E->get().first, dst_time);
  1330. Pair<int, real_t> p;
  1331. p.first = E->get().first;
  1332. p.second = dst_time;
  1333. new_selection_values.push_back(p);
  1334. if (existing_idx != -1) {
  1335. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, dst_time, animation->track_get_key_value(E->get().first, existing_idx), animation->track_get_key_transition(E->get().first, existing_idx));
  1336. }
  1337. }
  1338. undo_redo->commit_action();
  1339. //reselect duplicated
  1340. selection.clear();
  1341. for (const Pair<int, real_t> &E : new_selection_values) {
  1342. int track = E.first;
  1343. real_t time = E.second;
  1344. int existing_idx = animation->track_find_key(track, time, true);
  1345. if (existing_idx == -1) {
  1346. continue;
  1347. }
  1348. selection.insert(IntPair(track, existing_idx));
  1349. }
  1350. queue_redraw();
  1351. }
  1352. void AnimationBezierTrackEdit::delete_selection() {
  1353. if (selection.size()) {
  1354. undo_redo->create_action(TTR("Anim Delete Keys"));
  1355. for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
  1356. undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->get().first, E->get().second);
  1357. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->get().first, animation->track_get_key_time(E->get().first, E->get().second), animation->track_get_key_value(E->get().first, E->get().second), 1);
  1358. }
  1359. undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
  1360. undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
  1361. undo_redo->commit_action();
  1362. //selection.clear();
  1363. }
  1364. }
  1365. void AnimationBezierTrackEdit::_bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle, const Animation::HandleMode p_handle_mode) {
  1366. ERR_FAIL_COND(animation.is_null());
  1367. int idx = animation->bezier_track_insert_key(p_track, p_time, p_value, p_in_handle, p_out_handle);
  1368. animation->bezier_track_set_key_handle_mode(p_track, idx, p_handle_mode);
  1369. }
  1370. void AnimationBezierTrackEdit::_bind_methods() {
  1371. ClassDB::bind_method(D_METHOD("_clear_selection"), &AnimationBezierTrackEdit::_clear_selection);
  1372. ClassDB::bind_method(D_METHOD("_clear_selection_for_anim"), &AnimationBezierTrackEdit::_clear_selection_for_anim);
  1373. ClassDB::bind_method(D_METHOD("_select_at_anim"), &AnimationBezierTrackEdit::_select_at_anim);
  1374. ClassDB::bind_method(D_METHOD("_update_hidden_tracks_after"), &AnimationBezierTrackEdit::_update_hidden_tracks_after);
  1375. ClassDB::bind_method(D_METHOD("_update_locked_tracks_after"), &AnimationBezierTrackEdit::_update_locked_tracks_after);
  1376. ClassDB::bind_method(D_METHOD("_bezier_track_insert_key"), &AnimationBezierTrackEdit::_bezier_track_insert_key);
  1377. ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::FLOAT, "position"), PropertyInfo(Variant::BOOL, "drag")));
  1378. ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track")));
  1379. ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::FLOAT, "offset")));
  1380. ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single"), PropertyInfo(Variant::INT, "track")));
  1381. ADD_SIGNAL(MethodInfo("clear_selection"));
  1382. ADD_SIGNAL(MethodInfo("close_request"));
  1383. ADD_SIGNAL(MethodInfo("move_selection_begin"));
  1384. ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::FLOAT, "offset")));
  1385. ADD_SIGNAL(MethodInfo("move_selection_commit"));
  1386. ADD_SIGNAL(MethodInfo("move_selection_cancel"));
  1387. }
  1388. AnimationBezierTrackEdit::AnimationBezierTrackEdit() {
  1389. panner.instantiate();
  1390. panner->set_callbacks(callable_mp(this, &AnimationBezierTrackEdit::_scroll_callback), callable_mp(this, &AnimationBezierTrackEdit::_pan_callback), callable_mp(this, &AnimationBezierTrackEdit::_zoom_callback));
  1391. play_position = memnew(Control);
  1392. play_position->set_mouse_filter(MOUSE_FILTER_PASS);
  1393. add_child(play_position);
  1394. play_position->set_anchors_and_offsets_preset(PRESET_FULL_RECT);
  1395. play_position->connect("draw", callable_mp(this, &AnimationBezierTrackEdit::_play_position_draw));
  1396. set_focus_mode(FOCUS_CLICK);
  1397. set_clip_contents(true);
  1398. ED_SHORTCUT("animation_bezier_editor/focus", TTR("Focus"), Key::F);
  1399. ED_SHORTCUT("animation_bezier_editor/select_all_keys", TTR("Select All Keys"), KeyModifierMask::CMD_OR_CTRL | Key::A);
  1400. ED_SHORTCUT("animation_bezier_editor/deselect_all_keys", TTR("Deselect All Keys"), KeyModifierMask::CMD_OR_CTRL | KeyModifierMask::SHIFT | Key::A);
  1401. menu = memnew(PopupMenu);
  1402. add_child(menu);
  1403. menu->connect("id_pressed", callable_mp(this, &AnimationBezierTrackEdit::_menu_selected));
  1404. }