animation_track_editor.cpp 160 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257
  1. /*************************************************************************/
  2. /* animation_track_editor.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 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_track_editor.h"
  31. #include "animation_track_editor_plugins.h"
  32. #include "core/os/keyboard.h"
  33. #include "editor/animation_bezier_editor.h"
  34. #include "editor/plugins/animation_player_editor_plugin.h"
  35. #include "editor_node.h"
  36. #include "editor_scale.h"
  37. #include "scene/main/viewport.h"
  38. #include "servers/audio/audio_stream.h"
  39. class AnimationTrackKeyEdit : public Object {
  40. GDCLASS(AnimationTrackKeyEdit, Object);
  41. public:
  42. bool setting;
  43. bool _hide_script_from_inspector() {
  44. return true;
  45. }
  46. bool _dont_undo_redo() {
  47. return true;
  48. }
  49. static void _bind_methods() {
  50. ClassDB::bind_method("_update_obj", &AnimationTrackKeyEdit::_update_obj);
  51. ClassDB::bind_method("_key_ofs_changed", &AnimationTrackKeyEdit::_key_ofs_changed);
  52. ClassDB::bind_method("_hide_script_from_inspector", &AnimationTrackKeyEdit::_hide_script_from_inspector);
  53. ClassDB::bind_method("get_root_path", &AnimationTrackKeyEdit::get_root_path);
  54. ClassDB::bind_method("_dont_undo_redo", &AnimationTrackKeyEdit::_dont_undo_redo);
  55. }
  56. //PopupDialog *ke_dialog;
  57. void _fix_node_path(Variant &value) {
  58. NodePath np = value;
  59. if (np == NodePath())
  60. return;
  61. Node *root = EditorNode::get_singleton()->get_tree()->get_root();
  62. Node *np_node = root->get_node(np);
  63. ERR_FAIL_COND(!np_node);
  64. Node *edited_node = root->get_node(base);
  65. ERR_FAIL_COND(!edited_node);
  66. value = edited_node->get_path_to(np_node);
  67. }
  68. void _update_obj(const Ref<Animation> &p_anim) {
  69. if (setting)
  70. return;
  71. if (!(animation == p_anim))
  72. return;
  73. notify_change();
  74. }
  75. void _key_ofs_changed(const Ref<Animation> &p_anim, float from, float to) {
  76. if (!(animation == p_anim))
  77. return;
  78. if (from != key_ofs)
  79. return;
  80. key_ofs = to;
  81. if (setting)
  82. return;
  83. notify_change();
  84. }
  85. bool _set(const StringName &p_name, const Variant &p_value) {
  86. int key = animation->track_find_key(track, key_ofs, true);
  87. ERR_FAIL_COND_V(key == -1, false);
  88. String name = p_name;
  89. if (name == "time" || name == "frame") {
  90. float new_time = p_value;
  91. if (name == "frame") {
  92. float fps = animation->get_step();
  93. if (fps > 0) {
  94. fps = 1.0 / fps;
  95. }
  96. new_time /= fps;
  97. }
  98. if (new_time == key_ofs)
  99. return true;
  100. int existing = animation->track_find_key(track, new_time, true);
  101. setting = true;
  102. undo_redo->create_action(TTR("Anim Change Keyframe Time"), UndoRedo::MERGE_ENDS);
  103. Variant val = animation->track_get_key_value(track, key);
  104. float trans = animation->track_get_key_transition(track, key);
  105. undo_redo->add_do_method(animation.ptr(), "track_remove_key", track, key);
  106. undo_redo->add_do_method(animation.ptr(), "track_insert_key", track, new_time, val, trans);
  107. undo_redo->add_do_method(this, "_key_ofs_changed", animation, key_ofs, new_time);
  108. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", track, new_time);
  109. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, key_ofs, val, trans);
  110. undo_redo->add_undo_method(this, "_key_ofs_changed", animation, new_time, key_ofs);
  111. if (existing != -1) {
  112. Variant v = animation->track_get_key_value(track, existing);
  113. trans = animation->track_get_key_transition(track, existing);
  114. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", track, new_time, v, trans);
  115. }
  116. undo_redo->commit_action();
  117. setting = false;
  118. return true;
  119. } else if (name == "easing") {
  120. float val = p_value;
  121. float prev_val = animation->track_get_key_transition(track, key);
  122. setting = true;
  123. undo_redo->create_action(TTR("Anim Change Transition"), UndoRedo::MERGE_ENDS);
  124. undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
  125. undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
  126. undo_redo->add_do_method(this, "_update_obj", animation);
  127. undo_redo->add_undo_method(this, "_update_obj", animation);
  128. undo_redo->commit_action();
  129. setting = false;
  130. return true;
  131. }
  132. switch (animation->track_get_type(track)) {
  133. case Animation::TYPE_TRANSFORM: {
  134. Dictionary d_old = animation->track_get_key_value(track, key);
  135. Dictionary d_new = d_old;
  136. d_new[p_name] = p_value;
  137. setting = true;
  138. undo_redo->create_action(TTR("Anim Change Transform"));
  139. undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
  140. undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
  141. undo_redo->add_do_method(this, "_update_obj", animation);
  142. undo_redo->add_undo_method(this, "_update_obj", animation);
  143. undo_redo->commit_action();
  144. setting = false;
  145. return true;
  146. } break;
  147. case Animation::TYPE_VALUE: {
  148. if (name == "value") {
  149. Variant value = p_value;
  150. if (value.get_type() == Variant::NODE_PATH) {
  151. _fix_node_path(value);
  152. }
  153. setting = true;
  154. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  155. Variant prev = animation->track_get_key_value(track, key);
  156. undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, value);
  157. undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, prev);
  158. undo_redo->add_do_method(this, "_update_obj", animation);
  159. undo_redo->add_undo_method(this, "_update_obj", animation);
  160. undo_redo->commit_action();
  161. setting = false;
  162. return true;
  163. }
  164. } break;
  165. case Animation::TYPE_METHOD: {
  166. Dictionary d_old = animation->track_get_key_value(track, key);
  167. Dictionary d_new = d_old;
  168. bool change_notify_deserved = false;
  169. bool mergeable = false;
  170. if (name == "name") {
  171. d_new["method"] = p_value;
  172. }
  173. if (name == "arg_count") {
  174. Vector<Variant> args = d_old["args"];
  175. args.resize(p_value);
  176. d_new["args"] = args;
  177. change_notify_deserved = true;
  178. }
  179. if (name.begins_with("args/")) {
  180. Vector<Variant> args = d_old["args"];
  181. int idx = name.get_slice("/", 1).to_int();
  182. ERR_FAIL_INDEX_V(idx, args.size(), false);
  183. String what = name.get_slice("/", 2);
  184. if (what == "type") {
  185. Variant::Type t = Variant::Type(int(p_value));
  186. if (t != args[idx].get_type()) {
  187. Variant::CallError err;
  188. if (Variant::can_convert(args[idx].get_type(), t)) {
  189. Variant old = args[idx];
  190. Variant *ptrs[1] = { &old };
  191. args.write[idx] = Variant::construct(t, (const Variant **)ptrs, 1, err);
  192. } else {
  193. args.write[idx] = Variant::construct(t, NULL, 0, err);
  194. }
  195. change_notify_deserved = true;
  196. d_new["args"] = args;
  197. }
  198. }
  199. if (what == "value") {
  200. Variant value = p_value;
  201. if (value.get_type() == Variant::NODE_PATH) {
  202. _fix_node_path(value);
  203. }
  204. args.write[idx] = value;
  205. d_new["args"] = args;
  206. mergeable = true;
  207. }
  208. }
  209. if (mergeable)
  210. undo_redo->create_action(TTR("Anim Change Call"), UndoRedo::MERGE_ENDS);
  211. else
  212. undo_redo->create_action(TTR("Anim Change Call"));
  213. Variant prev = animation->track_get_key_value(track, key);
  214. setting = true;
  215. undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, d_new);
  216. undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, d_old);
  217. undo_redo->add_do_method(this, "_update_obj", animation);
  218. undo_redo->add_undo_method(this, "_update_obj", animation);
  219. undo_redo->commit_action();
  220. setting = false;
  221. if (change_notify_deserved)
  222. notify_change();
  223. return true;
  224. } break;
  225. case Animation::TYPE_BEZIER: {
  226. if (name == "value") {
  227. Variant value = p_value;
  228. setting = true;
  229. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  230. float prev = animation->bezier_track_get_key_value(track, key);
  231. undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_value", track, key, value);
  232. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_value", track, key, prev);
  233. undo_redo->add_do_method(this, "_update_obj", animation);
  234. undo_redo->add_undo_method(this, "_update_obj", animation);
  235. undo_redo->commit_action();
  236. setting = false;
  237. return true;
  238. }
  239. if (name == "in_handle") {
  240. Variant value = p_value;
  241. setting = true;
  242. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  243. Vector2 prev = animation->bezier_track_get_key_in_handle(track, key);
  244. undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, value);
  245. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_in_handle", track, key, prev);
  246. undo_redo->add_do_method(this, "_update_obj", animation);
  247. undo_redo->add_undo_method(this, "_update_obj", animation);
  248. undo_redo->commit_action();
  249. setting = false;
  250. return true;
  251. }
  252. if (name == "out_handle") {
  253. Variant value = p_value;
  254. setting = true;
  255. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  256. Vector2 prev = animation->bezier_track_get_key_out_handle(track, key);
  257. undo_redo->add_do_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, value);
  258. undo_redo->add_undo_method(animation.ptr(), "bezier_track_set_key_out_handle", track, key, prev);
  259. undo_redo->add_do_method(this, "_update_obj", animation);
  260. undo_redo->add_undo_method(this, "_update_obj", animation);
  261. undo_redo->commit_action();
  262. setting = false;
  263. return true;
  264. }
  265. } break;
  266. case Animation::TYPE_AUDIO: {
  267. if (name == "stream") {
  268. Ref<AudioStream> stream = p_value;
  269. setting = true;
  270. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  271. RES prev = animation->audio_track_get_key_stream(track, key);
  272. undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_stream", track, key, stream);
  273. undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_stream", track, key, prev);
  274. undo_redo->add_do_method(this, "_update_obj", animation);
  275. undo_redo->add_undo_method(this, "_update_obj", animation);
  276. undo_redo->commit_action();
  277. setting = false;
  278. return true;
  279. }
  280. if (name == "start_offset") {
  281. float value = p_value;
  282. setting = true;
  283. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  284. float prev = animation->audio_track_get_key_start_offset(track, key);
  285. undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, value);
  286. undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_start_offset", track, key, prev);
  287. undo_redo->add_do_method(this, "_update_obj", animation);
  288. undo_redo->add_undo_method(this, "_update_obj", animation);
  289. undo_redo->commit_action();
  290. setting = false;
  291. return true;
  292. }
  293. if (name == "end_offset") {
  294. float value = p_value;
  295. setting = true;
  296. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  297. float prev = animation->audio_track_get_key_end_offset(track, key);
  298. undo_redo->add_do_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, value);
  299. undo_redo->add_undo_method(animation.ptr(), "audio_track_set_key_end_offset", track, key, prev);
  300. undo_redo->add_do_method(this, "_update_obj", animation);
  301. undo_redo->add_undo_method(this, "_update_obj", animation);
  302. undo_redo->commit_action();
  303. setting = false;
  304. return true;
  305. }
  306. } break;
  307. case Animation::TYPE_ANIMATION: {
  308. if (name == "animation") {
  309. StringName anim_name = p_value;
  310. setting = true;
  311. undo_redo->create_action(TTR("Anim Change Keyframe Value"), UndoRedo::MERGE_ENDS);
  312. StringName prev = animation->animation_track_get_key_animation(track, key);
  313. undo_redo->add_do_method(animation.ptr(), "animation_track_set_key_animation", track, key, anim_name);
  314. undo_redo->add_undo_method(animation.ptr(), "animation_track_set_key_animation", track, key, prev);
  315. undo_redo->add_do_method(this, "_update_obj", animation);
  316. undo_redo->add_undo_method(this, "_update_obj", animation);
  317. undo_redo->commit_action();
  318. setting = false;
  319. return true;
  320. }
  321. } break;
  322. }
  323. return false;
  324. }
  325. bool _get(const StringName &p_name, Variant &r_ret) const {
  326. int key = animation->track_find_key(track, key_ofs, true);
  327. ERR_FAIL_COND_V(key == -1, false);
  328. String name = p_name;
  329. if (name == "time") {
  330. r_ret = key_ofs;
  331. return true;
  332. } else if (name == "frame") {
  333. float fps = animation->get_step();
  334. if (fps > 0) {
  335. fps = 1.0 / fps;
  336. }
  337. r_ret = key_ofs * fps;
  338. return true;
  339. } else if (name == "easing") {
  340. r_ret = animation->track_get_key_transition(track, key);
  341. return true;
  342. }
  343. switch (animation->track_get_type(track)) {
  344. case Animation::TYPE_TRANSFORM: {
  345. Dictionary d = animation->track_get_key_value(track, key);
  346. ERR_FAIL_COND_V(!d.has(name), false);
  347. r_ret = d[p_name];
  348. return true;
  349. } break;
  350. case Animation::TYPE_VALUE: {
  351. if (name == "value") {
  352. r_ret = animation->track_get_key_value(track, key);
  353. return true;
  354. }
  355. } break;
  356. case Animation::TYPE_METHOD: {
  357. Dictionary d = animation->track_get_key_value(track, key);
  358. if (name == "name") {
  359. ERR_FAIL_COND_V(!d.has("method"), false);
  360. r_ret = d["method"];
  361. return true;
  362. }
  363. ERR_FAIL_COND_V(!d.has("args"), false);
  364. Vector<Variant> args = d["args"];
  365. if (name == "arg_count") {
  366. r_ret = args.size();
  367. return true;
  368. }
  369. if (name.begins_with("args/")) {
  370. int idx = name.get_slice("/", 1).to_int();
  371. ERR_FAIL_INDEX_V(idx, args.size(), false);
  372. String what = name.get_slice("/", 2);
  373. if (what == "type") {
  374. r_ret = args[idx].get_type();
  375. return true;
  376. }
  377. if (what == "value") {
  378. r_ret = args[idx];
  379. return true;
  380. }
  381. }
  382. } break;
  383. case Animation::TYPE_BEZIER: {
  384. if (name == "value") {
  385. r_ret = animation->bezier_track_get_key_value(track, key);
  386. return true;
  387. }
  388. if (name == "in_handle") {
  389. r_ret = animation->bezier_track_get_key_in_handle(track, key);
  390. return true;
  391. }
  392. if (name == "out_handle") {
  393. r_ret = animation->bezier_track_get_key_out_handle(track, key);
  394. return true;
  395. }
  396. } break;
  397. case Animation::TYPE_AUDIO: {
  398. if (name == "stream") {
  399. r_ret = animation->audio_track_get_key_stream(track, key);
  400. return true;
  401. }
  402. if (name == "start_offset") {
  403. r_ret = animation->audio_track_get_key_start_offset(track, key);
  404. return true;
  405. }
  406. if (name == "end_offset") {
  407. r_ret = animation->audio_track_get_key_end_offset(track, key);
  408. return true;
  409. }
  410. } break;
  411. case Animation::TYPE_ANIMATION: {
  412. if (name == "animation") {
  413. r_ret = animation->animation_track_get_key_animation(track, key);
  414. return true;
  415. }
  416. } break;
  417. }
  418. return false;
  419. }
  420. void _get_property_list(List<PropertyInfo> *p_list) const {
  421. if (animation.is_null())
  422. return;
  423. ERR_FAIL_INDEX(track, animation->get_track_count());
  424. int key = animation->track_find_key(track, key_ofs, true);
  425. ERR_FAIL_COND(key == -1);
  426. if (use_fps && animation->get_step() > 0) {
  427. float max_frame = animation->get_length() / animation->get_step();
  428. p_list->push_back(PropertyInfo(Variant::REAL, "frame", PROPERTY_HINT_RANGE, "0," + rtos(max_frame) + ",1"));
  429. } else {
  430. p_list->push_back(PropertyInfo(Variant::REAL, "time", PROPERTY_HINT_RANGE, "0," + rtos(animation->get_length()) + ",0.01"));
  431. }
  432. switch (animation->track_get_type(track)) {
  433. case Animation::TYPE_TRANSFORM: {
  434. p_list->push_back(PropertyInfo(Variant::VECTOR3, "location"));
  435. p_list->push_back(PropertyInfo(Variant::QUAT, "rotation"));
  436. p_list->push_back(PropertyInfo(Variant::VECTOR3, "scale"));
  437. } break;
  438. case Animation::TYPE_VALUE: {
  439. Variant v = animation->track_get_key_value(track, key);
  440. if (hint.type != Variant::NIL) {
  441. PropertyInfo pi = hint;
  442. pi.name = "value";
  443. p_list->push_back(pi);
  444. } else {
  445. PropertyHint hint = PROPERTY_HINT_NONE;
  446. String hint_string;
  447. if (v.get_type() == Variant::OBJECT) {
  448. //could actually check the object property if exists..? yes i will!
  449. Ref<Resource> res = v;
  450. if (res.is_valid()) {
  451. hint = PROPERTY_HINT_RESOURCE_TYPE;
  452. hint_string = res->get_class();
  453. }
  454. }
  455. if (v.get_type() != Variant::NIL)
  456. p_list->push_back(PropertyInfo(v.get_type(), "value", hint, hint_string));
  457. }
  458. } break;
  459. case Animation::TYPE_METHOD: {
  460. p_list->push_back(PropertyInfo(Variant::STRING, "name"));
  461. p_list->push_back(PropertyInfo(Variant::INT, "arg_count", PROPERTY_HINT_RANGE, "0,5,1"));
  462. Dictionary d = animation->track_get_key_value(track, key);
  463. ERR_FAIL_COND(!d.has("args"));
  464. Vector<Variant> args = d["args"];
  465. String vtypes;
  466. for (int i = 0; i < Variant::VARIANT_MAX; i++) {
  467. if (i > 0)
  468. vtypes += ",";
  469. vtypes += Variant::get_type_name(Variant::Type(i));
  470. }
  471. for (int i = 0; i < args.size(); i++) {
  472. p_list->push_back(PropertyInfo(Variant::INT, "args/" + itos(i) + "/type", PROPERTY_HINT_ENUM, vtypes));
  473. if (args[i].get_type() != Variant::NIL)
  474. p_list->push_back(PropertyInfo(args[i].get_type(), "args/" + itos(i) + "/value"));
  475. }
  476. } break;
  477. case Animation::TYPE_BEZIER: {
  478. p_list->push_back(PropertyInfo(Variant::REAL, "value"));
  479. p_list->push_back(PropertyInfo(Variant::VECTOR2, "in_handle"));
  480. p_list->push_back(PropertyInfo(Variant::VECTOR2, "out_handle"));
  481. } break;
  482. case Animation::TYPE_AUDIO: {
  483. p_list->push_back(PropertyInfo(Variant::OBJECT, "stream", PROPERTY_HINT_RESOURCE_TYPE, "AudioStream"));
  484. p_list->push_back(PropertyInfo(Variant::REAL, "start_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
  485. p_list->push_back(PropertyInfo(Variant::REAL, "end_offset", PROPERTY_HINT_RANGE, "0,3600,0.01,or_greater"));
  486. } break;
  487. case Animation::TYPE_ANIMATION: {
  488. String animations;
  489. if (root_path && root_path->has_node(animation->track_get_path(track))) {
  490. AnimationPlayer *ap = Object::cast_to<AnimationPlayer>(root_path->get_node(animation->track_get_path(track)));
  491. if (ap) {
  492. List<StringName> anims;
  493. ap->get_animation_list(&anims);
  494. for (List<StringName>::Element *E = anims.front(); E; E = E->next()) {
  495. if (animations != String()) {
  496. animations += ",";
  497. }
  498. animations += String(E->get());
  499. }
  500. }
  501. }
  502. if (animations != String()) {
  503. animations += ",";
  504. }
  505. animations += "[stop]";
  506. p_list->push_back(PropertyInfo(Variant::STRING, "animation", PROPERTY_HINT_ENUM, animations));
  507. } break;
  508. }
  509. if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
  510. p_list->push_back(PropertyInfo(Variant::REAL, "easing", PROPERTY_HINT_EXP_EASING));
  511. }
  512. }
  513. UndoRedo *undo_redo;
  514. Ref<Animation> animation;
  515. int track;
  516. float key_ofs;
  517. Node *root_path;
  518. PropertyInfo hint;
  519. NodePath base;
  520. bool use_fps;
  521. void notify_change() {
  522. _change_notify();
  523. }
  524. Node *get_root_path() {
  525. return root_path;
  526. }
  527. void set_use_fps(bool p_enable) {
  528. use_fps = p_enable;
  529. _change_notify();
  530. }
  531. AnimationTrackKeyEdit() {
  532. use_fps = false;
  533. key_ofs = 0;
  534. track = -1;
  535. setting = false;
  536. root_path = NULL;
  537. }
  538. };
  539. void AnimationTimelineEdit::_zoom_changed(double) {
  540. update();
  541. play_position->update();
  542. emit_signal("zoom_changed");
  543. }
  544. float AnimationTimelineEdit::get_zoom_scale() const {
  545. float zv = zoom->get_value();
  546. if (zv < 1) {
  547. zv = 1.0 - zv;
  548. return Math::pow(1.0f + zv, 8.0f) * 100;
  549. } else {
  550. return 1.0 / Math::pow(zv, 8.0f) * 100;
  551. }
  552. }
  553. void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
  554. if (editing)
  555. return;
  556. p_new_len = MAX(0.001, p_new_len);
  557. if (use_fps && animation->get_step() > 0) {
  558. p_new_len *= animation->get_step();
  559. }
  560. editing = true;
  561. undo_redo->create_action(TTR("Change Animation Length"));
  562. undo_redo->add_do_method(animation.ptr(), "set_length", p_new_len);
  563. undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length());
  564. undo_redo->commit_action();
  565. editing = false;
  566. update();
  567. emit_signal("length_changed", p_new_len);
  568. }
  569. void AnimationTimelineEdit::_anim_loop_pressed() {
  570. undo_redo->create_action(TTR("Change Animation Loop"));
  571. undo_redo->add_do_method(animation.ptr(), "set_loop", loop->is_pressed());
  572. undo_redo->add_undo_method(animation.ptr(), "set_loop", animation->has_loop());
  573. undo_redo->commit_action();
  574. }
  575. int AnimationTimelineEdit::get_buttons_width() const {
  576. Ref<Texture> interp_mode = get_icon("TrackContinuous", "EditorIcons");
  577. Ref<Texture> interp_type = get_icon("InterpRaw", "EditorIcons");
  578. Ref<Texture> loop_type = get_icon("InterpWrapClamp", "EditorIcons");
  579. Ref<Texture> remove_icon = get_icon("Remove", "EditorIcons");
  580. Ref<Texture> down_icon = get_icon("select_arrow", "Tree");
  581. int total_w = interp_mode->get_width() + interp_type->get_width() + loop_type->get_width() + remove_icon->get_width();
  582. total_w += (down_icon->get_width() + 4 * EDSCALE) * 4;
  583. return total_w;
  584. }
  585. int AnimationTimelineEdit::get_name_limit() const {
  586. Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons");
  587. int limit = MAX(name_limit, add_track->get_minimum_size().width + hsize_icon->get_width());
  588. limit = MIN(limit, get_size().width - get_buttons_width() - 1);
  589. return limit;
  590. }
  591. void AnimationTimelineEdit::_notification(int p_what) {
  592. if (p_what == NOTIFICATION_ENTER_TREE) {
  593. add_track->set_icon(get_icon("Add", "EditorIcons"));
  594. loop->set_icon(get_icon("Loop", "EditorIcons"));
  595. time_icon->set_texture(get_icon("Time", "EditorIcons"));
  596. add_track->get_popup()->clear();
  597. add_track->get_popup()->add_icon_item(get_icon("KeyValue", "EditorIcons"), TTR("Property Track"));
  598. add_track->get_popup()->add_icon_item(get_icon("KeyXform", "EditorIcons"), TTR("3D Transform Track"));
  599. add_track->get_popup()->add_icon_item(get_icon("KeyCall", "EditorIcons"), TTR("Call Method Track"));
  600. add_track->get_popup()->add_icon_item(get_icon("KeyBezier", "EditorIcons"), TTR("Bezier Curve Track"));
  601. add_track->get_popup()->add_icon_item(get_icon("KeyAudio", "EditorIcons"), TTR("Audio Playback Track"));
  602. add_track->get_popup()->add_icon_item(get_icon("KeyAnimation", "EditorIcons"), TTR("Animation Playback Track"));
  603. }
  604. if (p_what == NOTIFICATION_RESIZED) {
  605. len_hb->set_position(Vector2(get_size().width - get_buttons_width(), 0));
  606. len_hb->set_size(Size2(get_buttons_width(), get_size().height));
  607. }
  608. if (p_what == NOTIFICATION_DRAW) {
  609. int key_range = get_size().width - get_buttons_width() - get_name_limit();
  610. if (!animation.is_valid())
  611. return;
  612. Ref<Font> font = get_font("font", "Label");
  613. Color color = get_color("font_color", "Label");
  614. int zoomw = key_range;
  615. float scale = get_zoom_scale();
  616. int h = get_size().height;
  617. float l = animation->get_length();
  618. if (l <= 0)
  619. l = 0.001; //avoid crashor
  620. Ref<Texture> hsize_icon = get_icon("Hsize", "EditorIcons");
  621. hsize_rect = Rect2(get_name_limit() - hsize_icon->get_width() - 2 * EDSCALE, (get_size().height - hsize_icon->get_height()) / 2, hsize_icon->get_width(), hsize_icon->get_height());
  622. draw_texture(hsize_icon, hsize_rect.position);
  623. {
  624. float time_min = 0;
  625. float time_max = animation->get_length();
  626. for (int i = 0; i < animation->get_track_count(); i++) {
  627. if (animation->track_get_key_count(i) > 0) {
  628. float beg = animation->track_get_key_time(i, 0);
  629. /*if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
  630. beg += animation->bezier_track_get_key_in_handle(i, 0).x;
  631. }* not worth it since they have no use */
  632. if (beg < time_min)
  633. time_min = beg;
  634. float end = animation->track_get_key_time(i, animation->track_get_key_count(i) - 1);
  635. /*if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
  636. end += animation->bezier_track_get_key_out_handle(i, animation->track_get_key_count(i) - 1).x;
  637. } not worth it since they have no use */
  638. if (end > time_max)
  639. time_max = end;
  640. }
  641. }
  642. float extra = (zoomw / scale) * 0.5;
  643. //if (time_min < -0.001)
  644. // time_min -= extra;
  645. time_max += extra;
  646. set_min(time_min);
  647. set_max(time_max);
  648. if (zoomw / scale < (time_max - time_min)) {
  649. hscroll->show();
  650. } else {
  651. hscroll->hide();
  652. }
  653. }
  654. set_page(zoomw / scale);
  655. int end_px = (l - get_value()) * scale;
  656. int begin_px = -get_value() * scale;
  657. Color notimecol = get_color("dark_color_2", "Editor");
  658. Color timecolor = color;
  659. timecolor.a = 0.2;
  660. Color linecolor = color;
  661. linecolor.a = 0.2;
  662. {
  663. draw_rect(Rect2(Point2(get_name_limit(), 0), Point2(zoomw - 1, h)), notimecol);
  664. if (begin_px < zoomw && end_px > 0) {
  665. if (begin_px < 0)
  666. begin_px = 0;
  667. if (end_px > zoomw)
  668. end_px = zoomw;
  669. draw_rect(Rect2(Point2(get_name_limit() + begin_px, 0), Point2(end_px - begin_px - 1, h)), timecolor);
  670. }
  671. }
  672. Color color_time_sec = color;
  673. Color color_time_dec = color;
  674. color_time_dec.a *= 0.5;
  675. #define SC_ADJ 100
  676. int min = 30;
  677. int dec = 1;
  678. int step = 1;
  679. int decimals = 2;
  680. bool step_found = false;
  681. const int period_width = font->get_char_size('.').width;
  682. int max_digit_width = font->get_char_size('0').width;
  683. for (int i = 1; i <= 9; i++) {
  684. const int digit_width = font->get_char_size('0' + i).width;
  685. max_digit_width = MAX(digit_width, max_digit_width);
  686. }
  687. const int max_sc = int(Math::ceil(zoomw / scale));
  688. const int max_sc_width = String::num(max_sc).length() * max_digit_width;
  689. while (!step_found) {
  690. min = max_sc_width;
  691. if (decimals > 0)
  692. min += period_width + max_digit_width * decimals;
  693. static const int _multp[3] = { 1, 2, 5 };
  694. for (int i = 0; i < 3; i++) {
  695. step = (_multp[i] * dec);
  696. if (step * scale / SC_ADJ > min) {
  697. step_found = true;
  698. break;
  699. }
  700. }
  701. if (step_found)
  702. break;
  703. dec *= 10;
  704. decimals--;
  705. if (decimals < 0)
  706. decimals = 0;
  707. }
  708. if (use_fps) {
  709. float step_size = animation->get_step();
  710. if (step_size > 0) {
  711. int prev_frame_ofs = -10000000;
  712. for (int i = 0; i < zoomw; i++) {
  713. float pos = get_value() + double(i) / scale;
  714. float prev = get_value() + (double(i) - 1.0) / scale;
  715. int frame = pos / step_size;
  716. int prev_frame = prev / step_size;
  717. bool sub = Math::floor(prev) == Math::floor(pos);
  718. if (frame != prev_frame && i >= prev_frame_ofs) {
  719. draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE));
  720. draw_string(font, Point2(get_name_limit() + i + 3 * EDSCALE, (h - font->get_height()) / 2 + font->get_ascent()).floor(), itos(frame), sub ? color_time_dec : color_time_sec, zoomw - i);
  721. prev_frame_ofs = i + font->get_string_size(itos(frame)).x + 5 * EDSCALE;
  722. }
  723. }
  724. }
  725. } else {
  726. for (int i = 0; i < zoomw; i++) {
  727. float pos = get_value() + double(i) / scale;
  728. float prev = get_value() + (double(i) - 1.0) / scale;
  729. int sc = int(Math::floor(pos * SC_ADJ));
  730. int prev_sc = int(Math::floor(prev * SC_ADJ));
  731. bool sub = (sc % SC_ADJ);
  732. if ((sc / step) != (prev_sc / step) || (prev_sc < 0 && sc >= 0)) {
  733. int scd = sc < 0 ? prev_sc : sc;
  734. draw_line(Point2(get_name_limit() + i, 0), Point2(get_name_limit() + i, h), linecolor, Math::round(EDSCALE));
  735. draw_string(font, Point2(get_name_limit() + i + 3, (h - font->get_height()) / 2 + font->get_ascent()).floor(), String::num((scd - (scd % step)) / double(SC_ADJ), decimals), sub ? color_time_dec : color_time_sec, zoomw - i);
  736. }
  737. }
  738. }
  739. draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
  740. }
  741. }
  742. void AnimationTimelineEdit::set_animation(const Ref<Animation> &p_animation) {
  743. animation = p_animation;
  744. if (animation.is_valid()) {
  745. len_hb->show();
  746. add_track->show();
  747. play_position->show();
  748. } else {
  749. len_hb->hide();
  750. add_track->hide();
  751. play_position->hide();
  752. }
  753. update();
  754. update_values();
  755. }
  756. Size2 AnimationTimelineEdit::get_minimum_size() const {
  757. Size2 ms = add_track->get_minimum_size();
  758. Ref<Font> font = get_font("font", "Label");
  759. ms.height = MAX(ms.height, font->get_height());
  760. ms.width = get_buttons_width() + add_track->get_minimum_size().width + get_icon("Hsize", "EditorIcons")->get_width() + 2;
  761. return ms;
  762. }
  763. void AnimationTimelineEdit::set_undo_redo(UndoRedo *p_undo_redo) {
  764. undo_redo = p_undo_redo;
  765. }
  766. void AnimationTimelineEdit::set_zoom(Range *p_zoom) {
  767. zoom = p_zoom;
  768. zoom->connect("value_changed", this, "_zoom_changed");
  769. }
  770. void AnimationTimelineEdit::set_play_position(float p_pos) {
  771. play_position_pos = p_pos;
  772. play_position->update();
  773. }
  774. float AnimationTimelineEdit::get_play_position() const {
  775. return play_position_pos;
  776. }
  777. void AnimationTimelineEdit::update_play_position() {
  778. play_position->update();
  779. }
  780. void AnimationTimelineEdit::update_values() {
  781. if (!animation.is_valid() || editing)
  782. return;
  783. editing = true;
  784. if (use_fps && animation->get_step() > 0) {
  785. length->set_value(animation->get_length() / animation->get_step());
  786. length->set_step(1);
  787. length->set_tooltip(TTR("Animation length (frames)"));
  788. time_icon->set_tooltip(TTR("Animation length (frames)"));
  789. } else {
  790. length->set_value(animation->get_length());
  791. length->set_step(0.01);
  792. length->set_tooltip(TTR("Animation length (seconds)"));
  793. time_icon->set_tooltip(TTR("Animation length (seconds)"));
  794. }
  795. loop->set_pressed(animation->has_loop());
  796. editing = false;
  797. }
  798. void AnimationTimelineEdit::_play_position_draw() {
  799. if (!animation.is_valid() || play_position_pos < 0)
  800. return;
  801. float scale = get_zoom_scale();
  802. int h = play_position->get_size().height;
  803. int px = (-get_value() + play_position_pos) * scale + get_name_limit();
  804. if (px >= get_name_limit() && px < (play_position->get_size().width - get_buttons_width())) {
  805. Color color = get_color("accent_color", "Editor");
  806. play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE));
  807. }
  808. }
  809. void AnimationTimelineEdit::_gui_input(const Ref<InputEvent> &p_event) {
  810. Ref<InputEventMouseButton> mb = p_event;
  811. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && hsize_rect.has_point(mb->get_position())) {
  812. dragging_hsize = true;
  813. dragging_hsize_from = mb->get_position().x;
  814. dragging_hsize_at = name_limit;
  815. }
  816. if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && dragging_hsize) {
  817. dragging_hsize = false;
  818. }
  819. if (mb.is_valid() && mb->get_position().x > get_name_limit() && mb->get_position().x < (get_size().width - get_buttons_width())) {
  820. if (!panning_timeline && mb->get_button_index() == BUTTON_LEFT) {
  821. int x = mb->get_position().x - get_name_limit();
  822. float ofs = x / get_zoom_scale() + get_value();
  823. emit_signal("timeline_changed", ofs, false);
  824. dragging_timeline = true;
  825. }
  826. if (!dragging_timeline && mb->get_button_index() == BUTTON_MIDDLE) {
  827. int x = mb->get_position().x - get_name_limit();
  828. panning_timeline_from = x / get_zoom_scale();
  829. panning_timeline = true;
  830. panning_timeline_at = get_value();
  831. }
  832. }
  833. if (dragging_timeline && mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && !mb->is_pressed()) {
  834. dragging_timeline = false;
  835. }
  836. if (panning_timeline && mb.is_valid() && mb->get_button_index() == BUTTON_MIDDLE && !mb->is_pressed()) {
  837. panning_timeline = false;
  838. }
  839. Ref<InputEventMouseMotion> mm = p_event;
  840. if (mm.is_valid()) {
  841. if (dragging_hsize) {
  842. int ofs = mm->get_position().x - dragging_hsize_from;
  843. name_limit = dragging_hsize_at + ofs;
  844. update();
  845. emit_signal("name_limit_changed");
  846. play_position->update();
  847. }
  848. if (dragging_timeline) {
  849. int x = mm->get_position().x - get_name_limit();
  850. float ofs = x / get_zoom_scale() + get_value();
  851. emit_signal("timeline_changed", ofs, false);
  852. }
  853. if (panning_timeline) {
  854. int x = mm->get_position().x - get_name_limit();
  855. float ofs = x / get_zoom_scale();
  856. float diff = ofs - panning_timeline_from;
  857. set_value(panning_timeline_at - diff);
  858. }
  859. }
  860. }
  861. void AnimationTimelineEdit::set_use_fps(bool p_use_fps) {
  862. use_fps = p_use_fps;
  863. update_values();
  864. update();
  865. }
  866. bool AnimationTimelineEdit::is_using_fps() const {
  867. return use_fps;
  868. }
  869. void AnimationTimelineEdit::set_hscroll(HScrollBar *p_hscroll) {
  870. hscroll = p_hscroll;
  871. }
  872. void AnimationTimelineEdit::_track_added(int p_track) {
  873. emit_signal("track_added", p_track);
  874. }
  875. void AnimationTimelineEdit::_bind_methods() {
  876. ClassDB::bind_method("_zoom_changed", &AnimationTimelineEdit::_zoom_changed);
  877. ClassDB::bind_method("_anim_length_changed", &AnimationTimelineEdit::_anim_length_changed);
  878. ClassDB::bind_method("_anim_loop_pressed", &AnimationTimelineEdit::_anim_loop_pressed);
  879. ClassDB::bind_method("_play_position_draw", &AnimationTimelineEdit::_play_position_draw);
  880. ClassDB::bind_method("_gui_input", &AnimationTimelineEdit::_gui_input);
  881. ClassDB::bind_method("_track_added", &AnimationTimelineEdit::_track_added);
  882. ADD_SIGNAL(MethodInfo("zoom_changed"));
  883. ADD_SIGNAL(MethodInfo("name_limit_changed"));
  884. ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "position"), PropertyInfo(Variant::BOOL, "drag")));
  885. ADD_SIGNAL(MethodInfo("track_added", PropertyInfo(Variant::INT, "track")));
  886. ADD_SIGNAL(MethodInfo("length_changed", PropertyInfo(Variant::REAL, "size")));
  887. }
  888. AnimationTimelineEdit::AnimationTimelineEdit() {
  889. use_fps = false;
  890. editing = false;
  891. name_limit = 150;
  892. zoom = NULL;
  893. play_position_pos = 0;
  894. play_position = memnew(Control);
  895. play_position->set_mouse_filter(MOUSE_FILTER_PASS);
  896. add_child(play_position);
  897. play_position->set_anchors_and_margins_preset(PRESET_WIDE);
  898. play_position->connect("draw", this, "_play_position_draw");
  899. add_track = memnew(MenuButton);
  900. add_track->set_position(Vector2(0, 0));
  901. add_child(add_track);
  902. add_track->set_text(TTR("Add Track"));
  903. len_hb = memnew(HBoxContainer);
  904. Control *expander = memnew(Control);
  905. expander->set_h_size_flags(SIZE_EXPAND_FILL);
  906. len_hb->add_child(expander);
  907. time_icon = memnew(TextureRect);
  908. time_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
  909. time_icon->set_tooltip(TTR("Animation length (seconds)"));
  910. len_hb->add_child(time_icon);
  911. length = memnew(EditorSpinSlider);
  912. length->set_min(0.001);
  913. length->set_max(36000);
  914. length->set_step(0.01);
  915. length->set_allow_greater(true);
  916. length->set_custom_minimum_size(Vector2(70 * EDSCALE, 0));
  917. length->set_hide_slider(true);
  918. length->set_tooltip(TTR("Animation length (seconds)"));
  919. length->connect("value_changed", this, "_anim_length_changed");
  920. len_hb->add_child(length);
  921. loop = memnew(ToolButton);
  922. loop->set_tooltip(TTR("Animation Looping"));
  923. loop->connect("pressed", this, "_anim_loop_pressed");
  924. loop->set_toggle_mode(true);
  925. len_hb->add_child(loop);
  926. add_child(len_hb);
  927. add_track->hide();
  928. add_track->get_popup()->connect("index_pressed", this, "_track_added");
  929. len_hb->hide();
  930. panning_timeline = false;
  931. dragging_timeline = false;
  932. dragging_hsize = false;
  933. }
  934. ////////////////////////////////////
  935. void AnimationTrackEdit::_notification(int p_what) {
  936. if (p_what == NOTIFICATION_DRAW) {
  937. if (animation.is_null())
  938. return;
  939. ERR_FAIL_INDEX(track, animation->get_track_count());
  940. int limit = timeline->get_name_limit();
  941. if (has_focus()) {
  942. Color accent = get_color("accent_color", "Editor");
  943. accent.a *= 0.7;
  944. draw_rect(Rect2(Point2(), get_size()), accent, false);
  945. }
  946. Ref<Font> font = get_font("font", "Label");
  947. Color color = get_color("font_color", "Label");
  948. Ref<Texture> type_icons[6] = {
  949. get_icon("KeyValue", "EditorIcons"),
  950. get_icon("KeyXform", "EditorIcons"),
  951. get_icon("KeyCall", "EditorIcons"),
  952. get_icon("KeyBezier", "EditorIcons"),
  953. get_icon("KeyAudio", "EditorIcons"),
  954. get_icon("KeyAnimation", "EditorIcons")
  955. };
  956. int hsep = get_constant("hseparation", "ItemList");
  957. Color linecolor = color;
  958. linecolor.a = 0.2;
  959. // NAMES AND ICONS //
  960. {
  961. Ref<Texture> check = animation->track_is_enabled(track) ? get_icon("checked", "CheckBox") : get_icon("unchecked", "CheckBox");
  962. int ofs = in_group ? check->get_width() : 0; //not the best reference for margin but..
  963. check_rect = Rect2(Point2(ofs, int(get_size().height - check->get_height()) / 2), check->get_size());
  964. draw_texture(check, check_rect.position);
  965. ofs += check->get_width() + hsep;
  966. Ref<Texture> type_icon = type_icons[animation->track_get_type(track)];
  967. draw_texture(type_icon, Point2(ofs, int(get_size().height - type_icon->get_height()) / 2));
  968. ofs += type_icon->get_width() + hsep;
  969. NodePath path = animation->track_get_path(track);
  970. Node *node = NULL;
  971. if (root && root->has_node(path)) {
  972. node = root->get_node(path);
  973. }
  974. String text;
  975. Color text_color = color;
  976. if (node && EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
  977. text_color = get_color("accent_color", "Editor");
  978. }
  979. if (in_group) {
  980. if (animation->track_get_type(track) == Animation::TYPE_METHOD) {
  981. text = TTR("Functions:");
  982. } else if (animation->track_get_type(track) == Animation::TYPE_AUDIO) {
  983. text = TTR("Audio Clips:");
  984. } else if (animation->track_get_type(track) == Animation::TYPE_ANIMATION) {
  985. text = TTR("Anim Clips:");
  986. } else {
  987. text += path.get_concatenated_subnames();
  988. }
  989. text_color.a *= 0.7;
  990. } else if (node) {
  991. Ref<Texture> icon;
  992. if (has_icon(node->get_class(), "EditorIcons")) {
  993. icon = get_icon(node->get_class(), "EditorIcons");
  994. } else {
  995. icon = get_icon("Node", "EditorIcons");
  996. }
  997. draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
  998. icon_cache = icon;
  999. text = String() + node->get_name() + ":" + path.get_concatenated_subnames();
  1000. ofs += hsep;
  1001. ofs += icon->get_width();
  1002. } else {
  1003. icon_cache = type_icon;
  1004. text = path;
  1005. }
  1006. path_cache = text;
  1007. path_rect = Rect2(ofs, 0, limit - ofs - hsep, get_size().height);
  1008. Vector2 string_pos = Point2(ofs, (get_size().height - font->get_height()) / 2 + font->get_ascent());
  1009. string_pos = string_pos.floor();
  1010. draw_string(font, string_pos, text, text_color, limit - ofs - hsep);
  1011. draw_line(Point2(limit, 0), Point2(limit, get_size().height), linecolor, Math::round(EDSCALE));
  1012. }
  1013. // KEYFAMES //
  1014. draw_bg(limit, get_size().width - timeline->get_buttons_width());
  1015. {
  1016. float scale = timeline->get_zoom_scale();
  1017. int limit_end = get_size().width - timeline->get_buttons_width();
  1018. for (int i = 0; i < animation->track_get_key_count(track); i++) {
  1019. float offset = animation->track_get_key_time(track, i) - timeline->get_value();
  1020. if (editor->is_key_selected(track, i) && editor->is_moving_selection()) {
  1021. offset = editor->snap_time(offset + editor->get_moving_selection_offset());
  1022. }
  1023. offset = offset * scale + limit;
  1024. if (i < animation->track_get_key_count(track) - 1) {
  1025. float offset_n = animation->track_get_key_time(track, i + 1) - timeline->get_value();
  1026. if (editor->is_key_selected(track, i + 1) && editor->is_moving_selection()) {
  1027. offset_n = editor->snap_time(offset_n + editor->get_moving_selection_offset());
  1028. }
  1029. offset_n = offset_n * scale + limit;
  1030. draw_key_link(i, scale, int(offset), int(offset_n), limit, limit_end);
  1031. }
  1032. draw_key(i, scale, int(offset), editor->is_key_selected(track, i), limit, limit_end);
  1033. }
  1034. }
  1035. draw_fg(limit, get_size().width - timeline->get_buttons_width());
  1036. // BUTTONS //
  1037. {
  1038. Ref<Texture> wrap_icon[2] = {
  1039. get_icon("InterpWrapClamp", "EditorIcons"),
  1040. get_icon("InterpWrapLoop", "EditorIcons"),
  1041. };
  1042. Ref<Texture> interp_icon[3] = {
  1043. get_icon("InterpRaw", "EditorIcons"),
  1044. get_icon("InterpLinear", "EditorIcons"),
  1045. get_icon("InterpCubic", "EditorIcons")
  1046. };
  1047. Ref<Texture> cont_icon[4] = {
  1048. get_icon("TrackContinuous", "EditorIcons"),
  1049. get_icon("TrackDiscrete", "EditorIcons"),
  1050. get_icon("TrackTrigger", "EditorIcons"),
  1051. get_icon("TrackCapture", "EditorIcons")
  1052. };
  1053. int ofs = get_size().width - timeline->get_buttons_width();
  1054. Ref<Texture> down_icon = get_icon("select_arrow", "Tree");
  1055. draw_line(Point2(ofs, 0), Point2(ofs, get_size().height), linecolor, Math::round(EDSCALE));
  1056. ofs += hsep;
  1057. {
  1058. //callmode
  1059. Animation::UpdateMode update_mode;
  1060. if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
  1061. update_mode = animation->value_track_get_update_mode(track);
  1062. } else {
  1063. update_mode = Animation::UPDATE_CONTINUOUS;
  1064. }
  1065. Ref<Texture> update_icon = cont_icon[update_mode];
  1066. update_mode_rect.position.x = ofs;
  1067. update_mode_rect.position.y = int(get_size().height - update_icon->get_height()) / 2;
  1068. update_mode_rect.size = update_icon->get_size();
  1069. if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
  1070. draw_texture(update_icon, update_mode_rect.position);
  1071. }
  1072. //make it easier to click
  1073. update_mode_rect.position.y = 0;
  1074. update_mode_rect.size.y = get_size().height;
  1075. ofs += update_icon->get_width() + hsep;
  1076. update_mode_rect.size.x += hsep;
  1077. if (animation->track_get_type(track) == Animation::TYPE_VALUE) {
  1078. draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
  1079. update_mode_rect.size.x += down_icon->get_width();
  1080. bezier_edit_rect = Rect2();
  1081. } else if (animation->track_get_type(track) == Animation::TYPE_BEZIER) {
  1082. Ref<Texture> bezier_icon = get_icon("EditBezier", "EditorIcons");
  1083. update_mode_rect.size.x += down_icon->get_width();
  1084. bezier_edit_rect.position = update_mode_rect.position + (update_mode_rect.size - bezier_icon->get_size()) / 2;
  1085. bezier_edit_rect.size = bezier_icon->get_size();
  1086. draw_texture(bezier_icon, bezier_edit_rect.position);
  1087. update_mode_rect = Rect2();
  1088. } else {
  1089. update_mode_rect = Rect2();
  1090. bezier_edit_rect = Rect2();
  1091. }
  1092. ofs += down_icon->get_width();
  1093. draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
  1094. ofs += hsep;
  1095. }
  1096. {
  1097. //interp
  1098. Animation::InterpolationType interp_mode = animation->track_get_interpolation_type(track);
  1099. Ref<Texture> icon = interp_icon[interp_mode];
  1100. interp_mode_rect.position.x = ofs;
  1101. interp_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
  1102. interp_mode_rect.size = icon->get_size();
  1103. if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
  1104. draw_texture(icon, interp_mode_rect.position);
  1105. }
  1106. //make it easier to click
  1107. interp_mode_rect.position.y = 0;
  1108. interp_mode_rect.size.y = get_size().height;
  1109. ofs += icon->get_width() + hsep;
  1110. interp_mode_rect.size.x += hsep;
  1111. if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
  1112. draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
  1113. interp_mode_rect.size.x += down_icon->get_width();
  1114. } else {
  1115. interp_mode_rect = Rect2();
  1116. }
  1117. ofs += down_icon->get_width();
  1118. draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
  1119. ofs += hsep;
  1120. }
  1121. {
  1122. //loop
  1123. bool loop_wrap = animation->track_get_interpolation_loop_wrap(track);
  1124. Ref<Texture> icon = wrap_icon[loop_wrap ? 1 : 0];
  1125. loop_mode_rect.position.x = ofs;
  1126. loop_mode_rect.position.y = int(get_size().height - icon->get_height()) / 2;
  1127. loop_mode_rect.size = icon->get_size();
  1128. if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
  1129. draw_texture(icon, loop_mode_rect.position);
  1130. }
  1131. loop_mode_rect.position.y = 0;
  1132. loop_mode_rect.size.y = get_size().height;
  1133. ofs += icon->get_width() + hsep;
  1134. loop_mode_rect.size.x += hsep;
  1135. if (animation->track_get_type(track) == Animation::TYPE_VALUE || animation->track_get_type(track) == Animation::TYPE_TRANSFORM) {
  1136. draw_texture(down_icon, Vector2(ofs, int(get_size().height - down_icon->get_height()) / 2));
  1137. loop_mode_rect.size.x += down_icon->get_width();
  1138. } else {
  1139. loop_mode_rect = Rect2();
  1140. }
  1141. ofs += down_icon->get_width();
  1142. draw_line(Point2(ofs + hsep * 0.5, 0), Point2(ofs + hsep * 0.5, get_size().height), linecolor, Math::round(EDSCALE));
  1143. ofs += hsep;
  1144. }
  1145. {
  1146. //erase
  1147. Ref<Texture> icon = get_icon("Remove", "EditorIcons");
  1148. remove_rect.position.x = ofs + ((get_size().width - ofs) - icon->get_width()) / 2;
  1149. remove_rect.position.y = int(get_size().height - icon->get_height()) / 2;
  1150. remove_rect.size = icon->get_size();
  1151. draw_texture(icon, remove_rect.position);
  1152. }
  1153. }
  1154. if (in_group) {
  1155. draw_line(Vector2(timeline->get_name_limit(), get_size().height), get_size(), linecolor, Math::round(EDSCALE));
  1156. } else {
  1157. draw_line(Vector2(0, get_size().height), get_size(), linecolor, Math::round(EDSCALE));
  1158. }
  1159. if (dropping_at != 0) {
  1160. Color drop_color = get_color("accent_color", "Editor");
  1161. if (dropping_at < 0) {
  1162. draw_line(Vector2(0, 0), Vector2(get_size().width, 0), drop_color, Math::round(EDSCALE));
  1163. } else {
  1164. draw_line(Vector2(0, get_size().height), get_size(), drop_color, Math::round(EDSCALE));
  1165. }
  1166. }
  1167. }
  1168. if (p_what == NOTIFICATION_MOUSE_EXIT || p_what == NOTIFICATION_DRAG_END) {
  1169. cancel_drop();
  1170. }
  1171. }
  1172. int AnimationTrackEdit::get_key_height() const {
  1173. if (!animation.is_valid())
  1174. return 0;
  1175. return type_icon->get_height();
  1176. }
  1177. Rect2 AnimationTrackEdit::get_key_rect(int p_index, float p_pixels_sec) {
  1178. if (!animation.is_valid())
  1179. return Rect2();
  1180. Rect2 rect = Rect2(-type_icon->get_width() / 2, 0, type_icon->get_width(), get_size().height);
  1181. //make it a big easier to click
  1182. rect.position.x -= rect.size.x * 0.5;
  1183. rect.size.x *= 2;
  1184. return rect;
  1185. }
  1186. bool AnimationTrackEdit::is_key_selectable_by_distance() const {
  1187. return true;
  1188. }
  1189. void AnimationTrackEdit::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) {
  1190. if (p_next_x < p_clip_left)
  1191. return;
  1192. if (p_x > p_clip_right)
  1193. return;
  1194. Variant current = animation->track_get_key_value(get_track(), p_index);
  1195. Variant next = animation->track_get_key_value(get_track(), p_index + 1);
  1196. if (current != next)
  1197. return;
  1198. Color color = get_color("font_color", "Label");
  1199. color.a = 0.5;
  1200. int from_x = MAX(p_x, p_clip_left);
  1201. int to_x = MIN(p_next_x, p_clip_right);
  1202. draw_line(Point2(from_x + 1, get_size().height / 2), Point2(to_x, get_size().height / 2), color, Math::round(2 * EDSCALE));
  1203. }
  1204. void AnimationTrackEdit::draw_key(int p_index, float p_pixels_sec, int p_x, bool p_selected, int p_clip_left, int p_clip_right) {
  1205. if (!animation.is_valid())
  1206. return;
  1207. if (p_x < p_clip_left || p_x > p_clip_right)
  1208. return;
  1209. Vector2 ofs(p_x - type_icon->get_width() / 2, int(get_size().height - type_icon->get_height()) / 2);
  1210. if (animation->track_get_type(track) == Animation::TYPE_METHOD) {
  1211. Ref<Font> font = get_font("font", "Label");
  1212. Color color = get_color("font_color", "Label");
  1213. color.a = 0.5;
  1214. Dictionary d = animation->track_get_key_value(track, p_index);
  1215. String text;
  1216. if (d.has("method"))
  1217. text += String(d["method"]);
  1218. text += "(";
  1219. Vector<Variant> args;
  1220. if (d.has("args"))
  1221. args = d["args"];
  1222. for (int i = 0; i < args.size(); i++) {
  1223. if (i > 0)
  1224. text += ", ";
  1225. text += String(args[i]);
  1226. }
  1227. text += ")";
  1228. int limit = MAX(0, p_clip_right - p_x - type_icon->get_width());
  1229. if (limit > 0) {
  1230. draw_string(font, Vector2(p_x + type_icon->get_width(), int(get_size().height - font->get_height()) / 2 + font->get_ascent()), text, color, limit);
  1231. }
  1232. }
  1233. if (p_selected) {
  1234. draw_texture(selected_icon, ofs);
  1235. } else {
  1236. draw_texture(type_icon, ofs);
  1237. }
  1238. }
  1239. //helper
  1240. void AnimationTrackEdit::draw_rect_clipped(const Rect2 &p_rect, const Color &p_color, bool p_filled) {
  1241. int clip_left = timeline->get_name_limit();
  1242. int clip_right = get_size().width - timeline->get_buttons_width();
  1243. if (p_rect.position.x > clip_right)
  1244. return;
  1245. if (p_rect.position.x + p_rect.size.x < clip_left)
  1246. return;
  1247. Rect2 clip = Rect2(clip_left, 0, clip_right - clip_left, get_size().height);
  1248. draw_rect(clip.clip(p_rect), p_color, p_filled);
  1249. }
  1250. void AnimationTrackEdit::draw_bg(int p_clip_left, int p_clip_right) {
  1251. }
  1252. void AnimationTrackEdit::draw_fg(int p_clip_left, int p_clip_right) {
  1253. }
  1254. void AnimationTrackEdit::draw_texture_clipped(const Ref<Texture> &p_texture, const Vector2 &p_pos) {
  1255. draw_texture_region_clipped(p_texture, Rect2(p_pos, p_texture->get_size()), Rect2(Point2(), p_texture->get_size()));
  1256. }
  1257. void AnimationTrackEdit::draw_texture_region_clipped(const Ref<Texture> &p_texture, const Rect2 &p_rect, const Rect2 &p_region) {
  1258. int clip_left = timeline->get_name_limit();
  1259. int clip_right = get_size().width - timeline->get_buttons_width();
  1260. //clip left and right
  1261. if (clip_left > p_rect.position.x + p_rect.size.x)
  1262. return;
  1263. if (clip_right < p_rect.position.x)
  1264. return;
  1265. Rect2 rect = p_rect;
  1266. Rect2 region = p_region;
  1267. if (clip_left > rect.position.x) {
  1268. int rect_pixels = (clip_left - rect.position.x);
  1269. int region_pixels = rect_pixels * region.size.x / rect.size.x;
  1270. rect.position.x += rect_pixels;
  1271. rect.size.x -= rect_pixels;
  1272. region.position.x += region_pixels;
  1273. region.size.x -= region_pixels;
  1274. }
  1275. if (clip_right < rect.position.x + rect.size.x) {
  1276. int rect_pixels = rect.position.x + rect.size.x - clip_right;
  1277. int region_pixels = rect_pixels * region.size.x / rect.size.x;
  1278. rect.size.x -= rect_pixels;
  1279. region.size.x -= region_pixels;
  1280. }
  1281. draw_texture_rect_region(p_texture, rect, region);
  1282. }
  1283. int AnimationTrackEdit::get_track() const {
  1284. return track;
  1285. }
  1286. Ref<Animation> AnimationTrackEdit::get_animation() const {
  1287. return animation;
  1288. }
  1289. void AnimationTrackEdit::set_animation_and_track(const Ref<Animation> &p_animation, int p_track) {
  1290. animation = p_animation;
  1291. track = p_track;
  1292. update();
  1293. Ref<Texture> type_icons[6] = {
  1294. get_icon("KeyValue", "EditorIcons"),
  1295. get_icon("KeyXform", "EditorIcons"),
  1296. get_icon("KeyCall", "EditorIcons"),
  1297. get_icon("KeyBezier", "EditorIcons"),
  1298. get_icon("KeyAudio", "EditorIcons"),
  1299. get_icon("KeyAnimation", "EditorIcons")
  1300. };
  1301. ERR_FAIL_INDEX(track, animation->get_track_count());
  1302. node_path = animation->track_get_path(p_track);
  1303. type_icon = type_icons[animation->track_get_type(track)];
  1304. selected_icon = get_icon("KeySelected", "EditorIcons");
  1305. }
  1306. NodePath AnimationTrackEdit::get_path() const {
  1307. return node_path;
  1308. }
  1309. Size2 AnimationTrackEdit::get_minimum_size() const {
  1310. Ref<Texture> texture = get_icon("Object", "EditorIcons");
  1311. Ref<Font> font = get_font("font", "Label");
  1312. int separation = get_constant("vseparation", "ItemList");
  1313. int max_h = MAX(texture->get_height(), font->get_height());
  1314. max_h = MAX(max_h, get_key_height());
  1315. return Vector2(1, max_h + separation);
  1316. }
  1317. void AnimationTrackEdit::set_undo_redo(UndoRedo *p_undo_redo) {
  1318. undo_redo = p_undo_redo;
  1319. }
  1320. void AnimationTrackEdit::set_timeline(AnimationTimelineEdit *p_timeline) {
  1321. timeline = p_timeline;
  1322. timeline->connect("zoom_changed", this, "_zoom_changed");
  1323. timeline->connect("name_limit_changed", this, "_zoom_changed");
  1324. }
  1325. void AnimationTrackEdit::set_editor(AnimationTrackEditor *p_editor) {
  1326. editor = p_editor;
  1327. }
  1328. void AnimationTrackEdit::_play_position_draw() {
  1329. if (!animation.is_valid() || play_position_pos < 0)
  1330. return;
  1331. float scale = timeline->get_zoom_scale();
  1332. int h = get_size().height;
  1333. int px = (-timeline->get_value() + play_position_pos) * scale + timeline->get_name_limit();
  1334. if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
  1335. Color color = get_color("accent_color", "Editor");
  1336. play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE));
  1337. }
  1338. }
  1339. void AnimationTrackEdit::set_play_position(float p_pos) {
  1340. play_position_pos = p_pos;
  1341. play_position->update();
  1342. }
  1343. void AnimationTrackEdit::update_play_position() {
  1344. play_position->update();
  1345. }
  1346. void AnimationTrackEdit::set_root(Node *p_root) {
  1347. root = p_root;
  1348. }
  1349. void AnimationTrackEdit::_zoom_changed() {
  1350. update();
  1351. play_position->update();
  1352. }
  1353. void AnimationTrackEdit::_path_entered(const String &p_text) {
  1354. undo_redo->create_action(TTR("Change Track Path"));
  1355. undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text);
  1356. undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
  1357. undo_redo->commit_action();
  1358. }
  1359. String AnimationTrackEdit::get_tooltip(const Point2 &p_pos) const {
  1360. if (check_rect.has_point(p_pos)) {
  1361. return TTR("Toggle this track on/off.");
  1362. }
  1363. if (path_rect.has_point(p_pos)) {
  1364. return animation->track_get_path(track);
  1365. }
  1366. if (update_mode_rect.has_point(p_pos)) {
  1367. return TTR("Update Mode (How this property is set)");
  1368. }
  1369. if (interp_mode_rect.has_point(p_pos)) {
  1370. return TTR("Interpolation Mode");
  1371. }
  1372. if (loop_mode_rect.has_point(p_pos)) {
  1373. return TTR("Loop Wrap Mode (Interpolate end with beginning on loop)");
  1374. }
  1375. if (remove_rect.has_point(p_pos)) {
  1376. return TTR("Remove this track.");
  1377. }
  1378. if (p_pos.x >= timeline->get_name_limit() && p_pos.x <= (get_size().width - timeline->get_buttons_width())) {
  1379. int key_idx = -1;
  1380. float key_distance = 1e20;
  1381. for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) { //select should happen in the opposite order of drawing for more accurate overlap select
  1382. Rect2 rect = const_cast<AnimationTrackEdit *>(this)->get_key_rect(i, timeline->get_zoom_scale());
  1383. float offset = animation->track_get_key_time(track, i) - timeline->get_value();
  1384. offset = offset * timeline->get_zoom_scale() + timeline->get_name_limit();
  1385. rect.position.x += offset;
  1386. if (rect.has_point(p_pos)) {
  1387. if (const_cast<AnimationTrackEdit *>(this)->is_key_selectable_by_distance()) {
  1388. float distance = ABS(offset - p_pos.x);
  1389. if (key_idx == -1 || distance < key_distance) {
  1390. key_idx = i;
  1391. key_distance = distance;
  1392. }
  1393. } else {
  1394. //first one does it
  1395. break;
  1396. }
  1397. }
  1398. }
  1399. if (key_idx != -1) {
  1400. String text = TTR("Time (s): ") + rtos(animation->track_get_key_time(track, key_idx)) + "\n";
  1401. switch (animation->track_get_type(track)) {
  1402. case Animation::TYPE_TRANSFORM: {
  1403. Dictionary d = animation->track_get_key_value(track, key_idx);
  1404. if (d.has("location"))
  1405. text += "Pos: " + String(d["location"]) + "\n";
  1406. if (d.has("rotation"))
  1407. text += "Rot: " + String(d["rotation"]) + "\n";
  1408. if (d.has("scale"))
  1409. text += "Scale: " + String(d["scale"]) + "\n";
  1410. } break;
  1411. case Animation::TYPE_VALUE: {
  1412. Variant v = animation->track_get_key_value(track, key_idx);
  1413. //text+="value: "+String(v)+"\n";
  1414. bool prop_exists = false;
  1415. Variant::Type valid_type = Variant::NIL;
  1416. Object *obj = NULL;
  1417. RES res;
  1418. Vector<StringName> leftover_path;
  1419. Node *node = root->get_node_and_resource(animation->track_get_path(track), res, leftover_path);
  1420. if (res.is_valid()) {
  1421. obj = res.ptr();
  1422. } else if (node) {
  1423. obj = node;
  1424. }
  1425. if (obj) {
  1426. valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);
  1427. }
  1428. text += "Type: " + Variant::get_type_name(v.get_type()) + "\n";
  1429. if (prop_exists && !Variant::can_convert(v.get_type(), valid_type)) {
  1430. text += "Value: " + String(v) + " (Invalid, expected type: " + Variant::get_type_name(valid_type) + ")\n";
  1431. } else {
  1432. text += "Value: " + String(v) + "\n";
  1433. }
  1434. text += "Easing: " + rtos(animation->track_get_key_transition(track, key_idx));
  1435. } break;
  1436. case Animation::TYPE_METHOD: {
  1437. Dictionary d = animation->track_get_key_value(track, key_idx);
  1438. if (d.has("method"))
  1439. text += String(d["method"]);
  1440. text += "(";
  1441. Vector<Variant> args;
  1442. if (d.has("args"))
  1443. args = d["args"];
  1444. for (int i = 0; i < args.size(); i++) {
  1445. if (i > 0)
  1446. text += ", ";
  1447. text += String(args[i]);
  1448. }
  1449. text += ")\n";
  1450. } break;
  1451. case Animation::TYPE_BEZIER: {
  1452. float h = animation->bezier_track_get_key_value(track, key_idx);
  1453. text += "Value: " + rtos(h) + "\n";
  1454. Vector2 ih = animation->bezier_track_get_key_in_handle(track, key_idx);
  1455. text += "In-Handle: " + ih + "\n";
  1456. Vector2 oh = animation->bezier_track_get_key_out_handle(track, key_idx);
  1457. text += "Out-Handle: " + oh + "\n";
  1458. } break;
  1459. case Animation::TYPE_AUDIO: {
  1460. String stream_name = "null";
  1461. RES stream = animation->audio_track_get_key_stream(track, key_idx);
  1462. if (stream.is_valid()) {
  1463. if (stream->get_path().is_resource_file()) {
  1464. stream_name = stream->get_path().get_file();
  1465. } else if (stream->get_name() != "") {
  1466. stream_name = stream->get_name();
  1467. } else {
  1468. stream_name = stream->get_class();
  1469. }
  1470. }
  1471. text += "Stream: " + stream_name + "\n";
  1472. float so = animation->audio_track_get_key_start_offset(track, key_idx);
  1473. text += "Start (s): " + rtos(so) + "\n";
  1474. float eo = animation->audio_track_get_key_end_offset(track, key_idx);
  1475. text += "End (s): " + rtos(eo) + "\n";
  1476. } break;
  1477. case Animation::TYPE_ANIMATION: {
  1478. String name = animation->animation_track_get_key_animation(track, key_idx);
  1479. text += "Animation Clip: " + name + "\n";
  1480. } break;
  1481. }
  1482. return text;
  1483. }
  1484. }
  1485. return Control::get_tooltip(p_pos);
  1486. }
  1487. void AnimationTrackEdit::_gui_input(const Ref<InputEvent> &p_event) {
  1488. if (p_event->is_pressed()) {
  1489. if (ED_GET_SHORTCUT("animation_editor/duplicate_selection")->is_shortcut(p_event)) {
  1490. emit_signal("duplicate_request");
  1491. accept_event();
  1492. }
  1493. if (ED_GET_SHORTCUT("animation_editor/duplicate_selection_transposed")->is_shortcut(p_event)) {
  1494. emit_signal("duplicate_transpose_request");
  1495. accept_event();
  1496. }
  1497. if (ED_GET_SHORTCUT("animation_editor/delete_selection")->is_shortcut(p_event)) {
  1498. emit_signal("delete_request");
  1499. accept_event();
  1500. }
  1501. }
  1502. Ref<InputEventMouseButton> mb = p_event;
  1503. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
  1504. Point2 pos = mb->get_position();
  1505. if (check_rect.has_point(pos)) {
  1506. undo_redo->create_action(TTR("Toggle Track Enabled"));
  1507. undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
  1508. undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
  1509. undo_redo->commit_action();
  1510. update();
  1511. accept_event();
  1512. }
  1513. if (path_rect.has_point(pos)) {
  1514. clicking_on_name = true;
  1515. accept_event();
  1516. }
  1517. if (update_mode_rect.has_point(pos)) {
  1518. if (!menu) {
  1519. menu = memnew(PopupMenu);
  1520. add_child(menu);
  1521. menu->connect("id_pressed", this, "_menu_selected");
  1522. }
  1523. menu->clear();
  1524. menu->add_icon_item(get_icon("TrackContinuous", "EditorIcons"), TTR("Continuous"), MENU_CALL_MODE_CONTINUOUS);
  1525. menu->add_icon_item(get_icon("TrackDiscrete", "EditorIcons"), TTR("Discrete"), MENU_CALL_MODE_DISCRETE);
  1526. menu->add_icon_item(get_icon("TrackTrigger", "EditorIcons"), TTR("Trigger"), MENU_CALL_MODE_TRIGGER);
  1527. menu->add_icon_item(get_icon("TrackCapture", "EditorIcons"), TTR("Capture"), MENU_CALL_MODE_CAPTURE);
  1528. menu->set_as_minsize();
  1529. Vector2 popup_pos = get_global_position() + update_mode_rect.position + Vector2(0, update_mode_rect.size.height);
  1530. menu->set_global_position(popup_pos);
  1531. menu->popup();
  1532. accept_event();
  1533. }
  1534. if (interp_mode_rect.has_point(pos)) {
  1535. if (!menu) {
  1536. menu = memnew(PopupMenu);
  1537. add_child(menu);
  1538. menu->connect("id_pressed", this, "_menu_selected");
  1539. }
  1540. menu->clear();
  1541. menu->add_icon_item(get_icon("InterpRaw", "EditorIcons"), TTR("Nearest"), MENU_INTERPOLATION_NEAREST);
  1542. menu->add_icon_item(get_icon("InterpLinear", "EditorIcons"), TTR("Linear"), MENU_INTERPOLATION_LINEAR);
  1543. menu->add_icon_item(get_icon("InterpCubic", "EditorIcons"), TTR("Cubic"), MENU_INTERPOLATION_CUBIC);
  1544. menu->set_as_minsize();
  1545. Vector2 popup_pos = get_global_position() + interp_mode_rect.position + Vector2(0, interp_mode_rect.size.height);
  1546. menu->set_global_position(popup_pos);
  1547. menu->popup();
  1548. accept_event();
  1549. }
  1550. if (loop_mode_rect.has_point(pos)) {
  1551. if (!menu) {
  1552. menu = memnew(PopupMenu);
  1553. add_child(menu);
  1554. menu->connect("id_pressed", this, "_menu_selected");
  1555. }
  1556. menu->clear();
  1557. menu->add_icon_item(get_icon("InterpWrapClamp", "EditorIcons"), TTR("Clamp Loop Interp"), MENU_LOOP_CLAMP);
  1558. menu->add_icon_item(get_icon("InterpWrapLoop", "EditorIcons"), TTR("Wrap Loop Interp"), MENU_LOOP_WRAP);
  1559. menu->set_as_minsize();
  1560. Vector2 popup_pos = get_global_position() + loop_mode_rect.position + Vector2(0, loop_mode_rect.size.height);
  1561. menu->set_global_position(popup_pos);
  1562. menu->popup();
  1563. accept_event();
  1564. }
  1565. if (remove_rect.has_point(pos)) {
  1566. emit_signal("remove_request", track);
  1567. accept_event();
  1568. return;
  1569. }
  1570. if (bezier_edit_rect.has_point(pos)) {
  1571. emit_signal("bezier_edit");
  1572. accept_event();
  1573. }
  1574. //check keyframes
  1575. float scale = timeline->get_zoom_scale();
  1576. int limit = timeline->get_name_limit();
  1577. int limit_end = get_size().width - timeline->get_buttons_width();
  1578. if (pos.x >= limit && pos.x <= limit_end) {
  1579. int key_idx = -1;
  1580. float key_distance = 1e20;
  1581. for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) { //select should happen in the opposite order of drawing for more accurate overlap select
  1582. Rect2 rect = get_key_rect(i, scale);
  1583. float offset = animation->track_get_key_time(track, i) - timeline->get_value();
  1584. offset = offset * scale + limit;
  1585. rect.position.x += offset;
  1586. if (rect.has_point(pos)) {
  1587. if (is_key_selectable_by_distance()) {
  1588. float distance = ABS(offset - pos.x);
  1589. if (key_idx == -1 || distance < key_distance) {
  1590. key_idx = i;
  1591. key_distance = distance;
  1592. }
  1593. } else {
  1594. //first one does it
  1595. key_idx = i;
  1596. break;
  1597. }
  1598. }
  1599. }
  1600. if (key_idx != -1) {
  1601. if (mb->get_command() || mb->get_shift()) {
  1602. if (editor->is_key_selected(track, key_idx)) {
  1603. emit_signal("deselect_key", key_idx);
  1604. } else {
  1605. emit_signal("select_key", key_idx, false);
  1606. moving_selection_attempt = true;
  1607. select_single_attempt = -1;
  1608. moving_selection_from_ofs = (mb->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale();
  1609. }
  1610. } else {
  1611. if (!editor->is_key_selected(track, key_idx)) {
  1612. emit_signal("select_key", key_idx, true);
  1613. select_single_attempt = -1;
  1614. } else {
  1615. select_single_attempt = key_idx;
  1616. }
  1617. moving_selection_attempt = true;
  1618. moving_selection_from_ofs = (mb->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale();
  1619. }
  1620. accept_event();
  1621. } else {
  1622. emit_signal("clear_selection");
  1623. }
  1624. }
  1625. /*using focus instead
  1626. * if (!selected && pos.x >= timeline->get_name_limit() && pos.x < (get_size().width - timeline->get_buttons_width())) {
  1627. set_selected(true);
  1628. emit_signal("selected");
  1629. }
  1630. */
  1631. }
  1632. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
  1633. Point2 pos = mb->get_position();
  1634. if (pos.x >= timeline->get_name_limit() && pos.x <= get_size().width - timeline->get_buttons_width()) {
  1635. //can do something with menu too! show insert key
  1636. float offset = (pos.x - timeline->get_name_limit()) / timeline->get_zoom_scale();
  1637. if (!menu) {
  1638. menu = memnew(PopupMenu);
  1639. add_child(menu);
  1640. menu->connect("id_pressed", this, "_menu_selected");
  1641. }
  1642. menu->clear();
  1643. menu->add_icon_item(get_icon("Key", "EditorIcons"), TTR("Insert Key"), MENU_KEY_INSERT);
  1644. if (editor->is_selection_active()) {
  1645. menu->add_separator();
  1646. menu->add_icon_item(get_icon("Duplicate", "EditorIcons"), TTR("Duplicate Key(s)"), MENU_KEY_DUPLICATE);
  1647. menu->add_separator();
  1648. menu->add_icon_item(get_icon("Remove", "EditorIcons"), TTR("Delete Key(s)"), MENU_KEY_DELETE);
  1649. }
  1650. menu->set_as_minsize();
  1651. Vector2 popup_pos = get_global_transform().xform(get_local_mouse_position());
  1652. menu->set_global_position(popup_pos);
  1653. menu->popup();
  1654. insert_at_pos = offset + timeline->get_value();
  1655. accept_event();
  1656. }
  1657. }
  1658. if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && clicking_on_name) {
  1659. if (!path) {
  1660. path = memnew(LineEdit);
  1661. add_child(path);
  1662. path->set_as_toplevel(true);
  1663. path->connect("text_entered", this, "_path_entered");
  1664. }
  1665. path->set_text(animation->track_get_path(track));
  1666. Vector2 theme_ofs = path->get_stylebox("normal", "LineEdit")->get_offset();
  1667. path->set_position(get_global_position() + path_rect.position - theme_ofs);
  1668. path->set_size(path_rect.size);
  1669. path->show_modal();
  1670. path->grab_focus();
  1671. path->set_cursor_position(path->get_text().length());
  1672. clicking_on_name = false;
  1673. }
  1674. if (mb.is_valid() && moving_selection_attempt) {
  1675. if (!mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
  1676. moving_selection_attempt = false;
  1677. if (moving_selection) {
  1678. emit_signal("move_selection_commit");
  1679. } else if (select_single_attempt != -1) {
  1680. emit_signal("select_key", select_single_attempt, true);
  1681. }
  1682. moving_selection = false;
  1683. select_single_attempt = -1;
  1684. }
  1685. if (moving_selection && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) {
  1686. moving_selection_attempt = false;
  1687. moving_selection = false;
  1688. emit_signal("move_selection_cancel");
  1689. }
  1690. }
  1691. Ref<InputEventMouseMotion> mm = p_event;
  1692. if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT && moving_selection_attempt) {
  1693. if (!moving_selection) {
  1694. moving_selection = true;
  1695. emit_signal("move_selection_begin");
  1696. }
  1697. float new_ofs = (mm->get_position().x - timeline->get_name_limit()) / timeline->get_zoom_scale();
  1698. emit_signal("move_selection", new_ofs - moving_selection_from_ofs);
  1699. }
  1700. }
  1701. Variant AnimationTrackEdit::get_drag_data(const Point2 &p_point) {
  1702. if (!clicking_on_name)
  1703. return Variant();
  1704. Dictionary drag_data;
  1705. drag_data["type"] = "animation_track";
  1706. drag_data["index"] = track;
  1707. ToolButton *tb = memnew(ToolButton);
  1708. tb->set_text(path_cache);
  1709. tb->set_icon(icon_cache);
  1710. set_drag_preview(tb);
  1711. clicking_on_name = false;
  1712. return drag_data;
  1713. }
  1714. bool AnimationTrackEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
  1715. Dictionary d = p_data;
  1716. if (!d.has("type")) {
  1717. return false;
  1718. }
  1719. String type = d["type"];
  1720. if (type != "animation_track")
  1721. return false;
  1722. if (p_point.y < get_size().height / 2) {
  1723. dropping_at = -1;
  1724. } else {
  1725. dropping_at = 1;
  1726. }
  1727. const_cast<AnimationTrackEdit *>(this)->update();
  1728. const_cast<AnimationTrackEdit *>(this)->emit_signal("drop_attempted", track);
  1729. return true;
  1730. }
  1731. void AnimationTrackEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
  1732. Dictionary d = p_data;
  1733. if (!d.has("type")) {
  1734. return;
  1735. }
  1736. String type = d["type"];
  1737. if (type != "animation_track")
  1738. return;
  1739. int from_track = d["index"];
  1740. if (dropping_at < 0) {
  1741. emit_signal("dropped", from_track, track);
  1742. } else {
  1743. emit_signal("dropped", from_track, track + 1);
  1744. }
  1745. }
  1746. void AnimationTrackEdit::_menu_selected(int p_index) {
  1747. switch (p_index) {
  1748. case MENU_CALL_MODE_CONTINUOUS:
  1749. case MENU_CALL_MODE_DISCRETE:
  1750. case MENU_CALL_MODE_TRIGGER:
  1751. case MENU_CALL_MODE_CAPTURE: {
  1752. Animation::UpdateMode update_mode = Animation::UpdateMode(p_index);
  1753. undo_redo->create_action(TTR("Change Animation Update Mode"));
  1754. undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode);
  1755. undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track));
  1756. undo_redo->commit_action();
  1757. update();
  1758. } break;
  1759. case MENU_INTERPOLATION_NEAREST:
  1760. case MENU_INTERPOLATION_LINEAR:
  1761. case MENU_INTERPOLATION_CUBIC: {
  1762. Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST);
  1763. undo_redo->create_action(TTR("Change Animation Interpolation Mode"));
  1764. undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode);
  1765. undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track));
  1766. undo_redo->commit_action();
  1767. update();
  1768. } break;
  1769. case MENU_LOOP_WRAP:
  1770. case MENU_LOOP_CLAMP: {
  1771. bool loop_wrap = p_index == MENU_LOOP_WRAP;
  1772. undo_redo->create_action(TTR("Change Animation Loop Mode"));
  1773. undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap);
  1774. undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track));
  1775. undo_redo->commit_action();
  1776. update();
  1777. } break;
  1778. case MENU_KEY_INSERT: {
  1779. emit_signal("insert_key", insert_at_pos);
  1780. } break;
  1781. case MENU_KEY_DUPLICATE: {
  1782. emit_signal("duplicate_request");
  1783. } break;
  1784. case MENU_KEY_DELETE: {
  1785. emit_signal("delete_request");
  1786. } break;
  1787. }
  1788. }
  1789. void AnimationTrackEdit::cancel_drop() {
  1790. if (dropping_at != 0) {
  1791. dropping_at = 0;
  1792. update();
  1793. }
  1794. }
  1795. void AnimationTrackEdit::set_in_group(bool p_enable) {
  1796. in_group = p_enable;
  1797. update();
  1798. }
  1799. void AnimationTrackEdit::append_to_selection(const Rect2 &p_box) {
  1800. Rect2 select_rect(timeline->get_name_limit(), 0, get_size().width - timeline->get_name_limit() - timeline->get_buttons_width(), get_size().height);
  1801. select_rect = select_rect.clip(p_box);
  1802. for (int i = animation->track_get_key_count(track) - 1; i >= 0; i--) { //select should happen in the opposite order of drawing for more accurate overlap select
  1803. Rect2 rect = const_cast<AnimationTrackEdit *>(this)->get_key_rect(i, timeline->get_zoom_scale());
  1804. float offset = animation->track_get_key_time(track, i) - timeline->get_value();
  1805. offset = offset * timeline->get_zoom_scale() + timeline->get_name_limit();
  1806. rect.position.x += offset;
  1807. if (select_rect.intersects(rect)) {
  1808. emit_signal("select_key", i, false);
  1809. }
  1810. }
  1811. }
  1812. void AnimationTrackEdit::_bind_methods() {
  1813. ClassDB::bind_method("_zoom_changed", &AnimationTrackEdit::_zoom_changed);
  1814. ClassDB::bind_method("_menu_selected", &AnimationTrackEdit::_menu_selected);
  1815. ClassDB::bind_method("_gui_input", &AnimationTrackEdit::_gui_input);
  1816. ClassDB::bind_method("_path_entered", &AnimationTrackEdit::_path_entered);
  1817. ClassDB::bind_method("_play_position_draw", &AnimationTrackEdit::_play_position_draw);
  1818. ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "position"), PropertyInfo(Variant::BOOL, "drag")));
  1819. ADD_SIGNAL(MethodInfo("remove_request", PropertyInfo(Variant::INT, "track")));
  1820. ADD_SIGNAL(MethodInfo("dropped", PropertyInfo(Variant::INT, "from_track"), PropertyInfo(Variant::INT, "to_track")));
  1821. ADD_SIGNAL(MethodInfo("insert_key", PropertyInfo(Variant::REAL, "ofs")));
  1822. ADD_SIGNAL(MethodInfo("select_key", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "single")));
  1823. ADD_SIGNAL(MethodInfo("deselect_key", PropertyInfo(Variant::INT, "index")));
  1824. ADD_SIGNAL(MethodInfo("clear_selection"));
  1825. ADD_SIGNAL(MethodInfo("bezier_edit"));
  1826. ADD_SIGNAL(MethodInfo("move_selection_begin"));
  1827. ADD_SIGNAL(MethodInfo("move_selection", PropertyInfo(Variant::REAL, "ofs")));
  1828. ADD_SIGNAL(MethodInfo("move_selection_commit"));
  1829. ADD_SIGNAL(MethodInfo("move_selection_cancel"));
  1830. ADD_SIGNAL(MethodInfo("duplicate_request"));
  1831. ADD_SIGNAL(MethodInfo("duplicate_transpose_request"));
  1832. ADD_SIGNAL(MethodInfo("delete_request"));
  1833. }
  1834. AnimationTrackEdit::AnimationTrackEdit() {
  1835. undo_redo = NULL;
  1836. timeline = NULL;
  1837. root = NULL;
  1838. path = NULL;
  1839. menu = NULL;
  1840. clicking_on_name = false;
  1841. dropping_at = 0;
  1842. in_group = false;
  1843. moving_selection_attempt = false;
  1844. moving_selection = false;
  1845. select_single_attempt = -1;
  1846. play_position_pos = 0;
  1847. play_position = memnew(Control);
  1848. play_position->set_mouse_filter(MOUSE_FILTER_PASS);
  1849. add_child(play_position);
  1850. play_position->set_anchors_and_margins_preset(PRESET_WIDE);
  1851. play_position->connect("draw", this, "_play_position_draw");
  1852. set_focus_mode(FOCUS_CLICK);
  1853. set_mouse_filter(MOUSE_FILTER_PASS); //scroll has to work too for selection
  1854. }
  1855. //////////////////////////////////////
  1856. AnimationTrackEdit *AnimationTrackEditPlugin::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) {
  1857. if (get_script_instance()) {
  1858. Variant args[6] = {
  1859. p_object,
  1860. p_type,
  1861. p_property,
  1862. p_hint,
  1863. p_hint_string,
  1864. p_usage
  1865. };
  1866. Variant *argptrs[6] = {
  1867. &args[0],
  1868. &args[1],
  1869. &args[2],
  1870. &args[3],
  1871. &args[4],
  1872. &args[5]
  1873. };
  1874. Variant::CallError ce;
  1875. return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_value_track_edit", (const Variant **)&argptrs, 6, ce).operator Object *());
  1876. }
  1877. return NULL;
  1878. }
  1879. AnimationTrackEdit *AnimationTrackEditPlugin::create_audio_track_edit() {
  1880. if (get_script_instance()) {
  1881. return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_audio_track_edit").operator Object *());
  1882. }
  1883. return NULL;
  1884. }
  1885. AnimationTrackEdit *AnimationTrackEditPlugin::create_animation_track_edit(Object *p_object) {
  1886. if (get_script_instance()) {
  1887. return Object::cast_to<AnimationTrackEdit>(get_script_instance()->call("create_animation_track_edit", p_object).operator Object *());
  1888. }
  1889. return NULL;
  1890. }
  1891. ///////////////////////////////////////
  1892. void AnimationTrackEditGroup::_notification(int p_what) {
  1893. if (p_what == NOTIFICATION_DRAW) {
  1894. Ref<Font> font = get_font("font", "Label");
  1895. int separation = get_constant("hseparation", "ItemList");
  1896. Color color = get_color("font_color", "Label");
  1897. if (root && root->has_node(node)) {
  1898. Node *n = root->get_node(node);
  1899. if (n && EditorNode::get_singleton()->get_editor_selection()->is_selected(n)) {
  1900. color = get_color("accent_color", "Editor");
  1901. }
  1902. }
  1903. Color bgcol = get_color("dark_color_2", "Editor");
  1904. bgcol.a *= 0.6;
  1905. draw_rect(Rect2(Point2(), get_size()), bgcol);
  1906. Color linecolor = color;
  1907. linecolor.a = 0.2;
  1908. draw_line(Point2(), Point2(get_size().width, 0), linecolor, Math::round(EDSCALE));
  1909. draw_line(Point2(timeline->get_name_limit(), 0), Point2(timeline->get_name_limit(), get_size().height), linecolor, Math::round(EDSCALE));
  1910. draw_line(Point2(get_size().width - timeline->get_buttons_width(), 0), Point2(get_size().width - timeline->get_buttons_width(), get_size().height), linecolor, Math::round(EDSCALE));
  1911. int ofs = 0;
  1912. draw_texture(icon, Point2(ofs, int(get_size().height - icon->get_height()) / 2));
  1913. ofs += separation + icon->get_width();
  1914. draw_string(font, Point2(ofs, int(get_size().height - font->get_height()) / 2 + font->get_ascent()), node_name, color, timeline->get_name_limit() - ofs);
  1915. int px = (-timeline->get_value() + timeline->get_play_position()) * timeline->get_zoom_scale() + timeline->get_name_limit();
  1916. if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) {
  1917. Color accent = get_color("accent_color", "Editor");
  1918. draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(EDSCALE));
  1919. }
  1920. }
  1921. }
  1922. void AnimationTrackEditGroup::set_type_and_name(const Ref<Texture> &p_type, const String &p_name, const NodePath &p_node) {
  1923. icon = p_type;
  1924. node_name = p_name;
  1925. node = p_node;
  1926. update();
  1927. minimum_size_changed();
  1928. }
  1929. Size2 AnimationTrackEditGroup::get_minimum_size() const {
  1930. Ref<Font> font = get_font("font", "Label");
  1931. int separation = get_constant("vseparation", "ItemList");
  1932. return Vector2(0, MAX(font->get_height(), icon->get_height()) + separation);
  1933. }
  1934. void AnimationTrackEditGroup::set_timeline(AnimationTimelineEdit *p_timeline) {
  1935. timeline = p_timeline;
  1936. timeline->connect("zoom_changed", this, "_zoom_changed");
  1937. timeline->connect("name_limit_changed", this, "_zoom_changed");
  1938. }
  1939. void AnimationTrackEditGroup::set_root(Node *p_root) {
  1940. root = p_root;
  1941. update();
  1942. }
  1943. void AnimationTrackEditGroup::_zoom_changed() {
  1944. update();
  1945. }
  1946. void AnimationTrackEditGroup::_bind_methods() {
  1947. ClassDB::bind_method("_zoom_changed", &AnimationTrackEditGroup::_zoom_changed);
  1948. }
  1949. AnimationTrackEditGroup::AnimationTrackEditGroup() {
  1950. set_mouse_filter(MOUSE_FILTER_PASS);
  1951. }
  1952. //////////////////////////////////////
  1953. void AnimationTrackEditor::add_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin) {
  1954. if (track_edit_plugins.find(p_plugin) != -1)
  1955. return;
  1956. track_edit_plugins.push_back(p_plugin);
  1957. }
  1958. void AnimationTrackEditor::remove_track_edit_plugin(const Ref<AnimationTrackEditPlugin> &p_plugin) {
  1959. track_edit_plugins.erase(p_plugin);
  1960. }
  1961. void AnimationTrackEditor::set_animation(const Ref<Animation> &p_anim) {
  1962. if (animation != p_anim && _get_track_selected() >= 0) {
  1963. track_edits[_get_track_selected()]->release_focus();
  1964. }
  1965. if (animation.is_valid()) {
  1966. animation->disconnect("changed", this, "_animation_changed");
  1967. _clear_selection();
  1968. }
  1969. animation = p_anim;
  1970. timeline->set_animation(p_anim);
  1971. _cancel_bezier_edit();
  1972. _update_tracks();
  1973. if (animation.is_valid()) {
  1974. animation->connect("changed", this, "_animation_changed");
  1975. hscroll->show();
  1976. edit->set_disabled(false);
  1977. step->set_block_signals(true);
  1978. _update_step_spinbox();
  1979. step->set_block_signals(false);
  1980. step->set_read_only(false);
  1981. snap->set_disabled(false);
  1982. snap_mode->set_disabled(false);
  1983. imported_anim_warning->hide();
  1984. for (int i = 0; i < animation->get_track_count(); i++) {
  1985. if (animation->track_is_imported(i)) {
  1986. imported_anim_warning->show();
  1987. break;
  1988. }
  1989. }
  1990. } else {
  1991. hscroll->hide();
  1992. edit->set_disabled(true);
  1993. step->set_block_signals(true);
  1994. step->set_value(0);
  1995. step->set_block_signals(false);
  1996. step->set_read_only(true);
  1997. snap->set_disabled(true);
  1998. snap_mode->set_disabled(true);
  1999. }
  2000. }
  2001. Ref<Animation> AnimationTrackEditor::get_current_animation() const {
  2002. return animation;
  2003. }
  2004. void AnimationTrackEditor::_root_removed(Node *p_root) {
  2005. root = NULL;
  2006. }
  2007. void AnimationTrackEditor::set_root(Node *p_root) {
  2008. if (root) {
  2009. root->disconnect("tree_exiting", this, "_root_removed");
  2010. }
  2011. root = p_root;
  2012. if (root) {
  2013. root->connect("tree_exiting", this, "_root_removed", make_binds(), CONNECT_ONESHOT);
  2014. }
  2015. _update_tracks();
  2016. }
  2017. Node *AnimationTrackEditor::get_root() const {
  2018. return root;
  2019. }
  2020. void AnimationTrackEditor::update_keying() {
  2021. bool keying_enabled = is_visible_in_tree() && animation.is_valid();
  2022. if (keying_enabled == keying)
  2023. return;
  2024. keying = keying_enabled;
  2025. //_update_menu();
  2026. emit_signal("keying_changed");
  2027. }
  2028. bool AnimationTrackEditor::has_keying() const {
  2029. return keying;
  2030. }
  2031. Dictionary AnimationTrackEditor::get_state() const {
  2032. Dictionary state;
  2033. state["fps_mode"] = timeline->is_using_fps();
  2034. state["zoom"] = zoom->get_value();
  2035. state["offset"] = timeline->get_value();
  2036. state["v_scroll"] = scroll->get_v_scrollbar()->get_value();
  2037. return state;
  2038. }
  2039. void AnimationTrackEditor::set_state(const Dictionary &p_state) {
  2040. if (p_state.has("fps_mode")) {
  2041. bool fps_mode = p_state["fps_mode"];
  2042. if (fps_mode) {
  2043. snap_mode->select(1);
  2044. } else {
  2045. snap_mode->select(0);
  2046. }
  2047. _snap_mode_changed(snap_mode->get_selected());
  2048. } else {
  2049. snap_mode->select(0);
  2050. _snap_mode_changed(snap_mode->get_selected());
  2051. }
  2052. if (p_state.has("zoom")) {
  2053. zoom->set_value(p_state["zoom"]);
  2054. } else {
  2055. zoom->set_value(1.0);
  2056. }
  2057. if (p_state.has("offset")) {
  2058. timeline->set_value(p_state["offset"]);
  2059. } else {
  2060. timeline->set_value(0);
  2061. }
  2062. if (p_state.has("v_scroll")) {
  2063. scroll->get_v_scrollbar()->set_value(p_state["v_scroll"]);
  2064. } else {
  2065. scroll->get_v_scrollbar()->set_value(0);
  2066. }
  2067. }
  2068. void AnimationTrackEditor::cleanup() {
  2069. set_animation(Ref<Animation>());
  2070. }
  2071. void AnimationTrackEditor::_name_limit_changed() {
  2072. for (int i = 0; i < track_edits.size(); i++) {
  2073. track_edits[i]->update();
  2074. }
  2075. }
  2076. void AnimationTrackEditor::_timeline_changed(float p_new_pos, bool p_drag) {
  2077. emit_signal("timeline_changed", p_new_pos, p_drag);
  2078. }
  2079. void AnimationTrackEditor::_track_remove_request(int p_track) {
  2080. int idx = p_track;
  2081. if (idx >= 0 && idx < animation->get_track_count()) {
  2082. selection.clear();
  2083. _clear_key_edit();
  2084. //all will be updated after remove anyway, and triggering update here raises error on tracks already removed
  2085. undo_redo->create_action(TTR("Remove Anim Track"));
  2086. undo_redo->add_do_method(animation.ptr(), "remove_track", idx);
  2087. undo_redo->add_undo_method(animation.ptr(), "add_track", animation->track_get_type(idx), idx);
  2088. undo_redo->add_undo_method(animation.ptr(), "track_set_path", idx, animation->track_get_path(idx));
  2089. //todo interpolation
  2090. for (int i = 0; i < animation->track_get_key_count(idx); i++) {
  2091. Variant v = animation->track_get_key_value(idx, i);
  2092. float time = animation->track_get_key_time(idx, i);
  2093. float trans = animation->track_get_key_transition(idx, i);
  2094. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", idx, time, v);
  2095. undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", idx, i, trans);
  2096. }
  2097. undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", idx, animation->track_get_interpolation_type(idx));
  2098. if (animation->track_get_type(idx) == Animation::TYPE_VALUE) {
  2099. undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", idx, animation->value_track_get_update_mode(idx));
  2100. }
  2101. undo_redo->commit_action();
  2102. }
  2103. }
  2104. void AnimationTrackEditor::set_anim_pos(float p_pos) {
  2105. timeline->set_play_position(p_pos);
  2106. for (int i = 0; i < track_edits.size(); i++) {
  2107. track_edits[i]->set_play_position(p_pos);
  2108. }
  2109. for (int i = 0; i < groups.size(); i++) {
  2110. groups[i]->update();
  2111. }
  2112. bezier_edit->set_play_position(p_pos);
  2113. }
  2114. void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
  2115. if (insert_frame != Engine::get_singleton()->get_frames_drawn()) {
  2116. //clear insert list for the frame if frame changed
  2117. if (insert_confirm->is_visible_in_tree())
  2118. return; //do nothing
  2119. insert_data.clear();
  2120. insert_query = false;
  2121. }
  2122. insert_frame = Engine::get_singleton()->get_frames_drawn();
  2123. for (List<InsertData>::Element *E = insert_data.front(); E; E = E->next()) {
  2124. //prevent insertion of multiple tracks
  2125. if (E->get().path == p_id.path)
  2126. return; //already inserted a track for this on this frame
  2127. }
  2128. insert_data.push_back(p_id);
  2129. if (p_id.track_idx == -1) {
  2130. if (bool(EDITOR_DEF("editors/animation/confirm_insert_track", true))) {
  2131. //potential new key, does not exist
  2132. if (insert_data.size() == 1)
  2133. insert_confirm_text->set_text(vformat(TTR("Create NEW track for %s and insert key?"), p_id.query));
  2134. else
  2135. insert_confirm_text->set_text(vformat(TTR("Create %d NEW tracks and insert keys?"), insert_data.size()));
  2136. bool all_bezier = true;
  2137. for (int i = 0; i < insert_data.size(); i++) {
  2138. if (insert_data[i].type != Animation::TYPE_VALUE && insert_data[i].type != Animation::TYPE_BEZIER) {
  2139. all_bezier = false;
  2140. }
  2141. if (insert_data[i].type != Animation::TYPE_VALUE) {
  2142. continue;
  2143. }
  2144. switch (insert_data[i].value.get_type()) {
  2145. case Variant::INT:
  2146. case Variant::REAL:
  2147. case Variant::VECTOR2:
  2148. case Variant::VECTOR3:
  2149. case Variant::QUAT:
  2150. case Variant::PLANE:
  2151. case Variant::COLOR: {
  2152. //good
  2153. } break;
  2154. default: {
  2155. all_bezier = false;
  2156. }
  2157. }
  2158. }
  2159. insert_confirm_bezier->set_visible(all_bezier);
  2160. insert_confirm->get_ok()->set_text(TTR("Create"));
  2161. insert_confirm->popup_centered_minsize();
  2162. insert_query = true;
  2163. } else {
  2164. call_deferred("_insert_delay");
  2165. insert_queue = true;
  2166. }
  2167. } else {
  2168. if (!insert_query && !insert_queue) {
  2169. call_deferred("_insert_delay");
  2170. insert_queue = true;
  2171. }
  2172. }
  2173. }
  2174. void AnimationTrackEditor::_insert_delay() {
  2175. if (insert_query) {
  2176. //discard since it's entered into query mode
  2177. insert_queue = false;
  2178. return;
  2179. }
  2180. undo_redo->create_action(TTR("Anim Insert"));
  2181. int last_track = animation->get_track_count();
  2182. bool advance = false;
  2183. while (insert_data.size()) {
  2184. if (insert_data.front()->get().advance)
  2185. advance = true;
  2186. last_track = _confirm_insert(insert_data.front()->get(), last_track);
  2187. insert_data.pop_front();
  2188. }
  2189. undo_redo->commit_action();
  2190. if (advance) {
  2191. float step = animation->get_step();
  2192. if (step == 0)
  2193. step = 1;
  2194. float pos = timeline->get_play_position();
  2195. pos = Math::stepify(pos + step, step);
  2196. if (pos > animation->get_length())
  2197. pos = animation->get_length();
  2198. set_anim_pos(pos);
  2199. emit_signal("timeline_changed", pos, true);
  2200. }
  2201. insert_queue = false;
  2202. }
  2203. void AnimationTrackEditor::insert_transform_key(Spatial *p_node, const String &p_sub, const Transform &p_xform) {
  2204. if (!keying)
  2205. return;
  2206. if (!animation.is_valid())
  2207. return;
  2208. ERR_FAIL_COND(!root);
  2209. //let's build a node path
  2210. String path = root->get_path_to(p_node);
  2211. if (p_sub != "")
  2212. path += ":" + p_sub;
  2213. NodePath np = path;
  2214. int track_idx = -1;
  2215. for (int i = 0; i < animation->get_track_count(); i++) {
  2216. if (animation->track_get_type(i) != Animation::TYPE_TRANSFORM)
  2217. continue;
  2218. if (animation->track_get_path(i) != np)
  2219. continue;
  2220. track_idx = i;
  2221. break;
  2222. }
  2223. InsertData id;
  2224. Dictionary val;
  2225. id.path = np;
  2226. id.track_idx = track_idx;
  2227. id.value = p_xform;
  2228. id.type = Animation::TYPE_TRANSFORM;
  2229. id.query = "node '" + p_node->get_name() + "'";
  2230. id.advance = false;
  2231. //dialog insert
  2232. _query_insert(id);
  2233. }
  2234. void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant &p_value) {
  2235. String path = p_path;
  2236. //animation property is a special case, always creates an animation track
  2237. for (int i = 0; i < animation->get_track_count(); i++) {
  2238. String np = animation->track_get_path(i);
  2239. if (path == np && animation->track_get_type(i) == Animation::TYPE_ANIMATION) {
  2240. //exists
  2241. InsertData id;
  2242. id.path = path;
  2243. id.track_idx = i;
  2244. id.value = p_value;
  2245. id.type = Animation::TYPE_ANIMATION;
  2246. id.query = "animation";
  2247. id.advance = false;
  2248. //dialog insert
  2249. _query_insert(id);
  2250. return;
  2251. }
  2252. }
  2253. InsertData id;
  2254. id.path = path;
  2255. id.track_idx = -1;
  2256. id.value = p_value;
  2257. id.type = Animation::TYPE_ANIMATION;
  2258. id.query = "animation";
  2259. id.advance = false;
  2260. //dialog insert
  2261. _query_insert(id);
  2262. }
  2263. void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) {
  2264. ERR_FAIL_COND(!root);
  2265. //let's build a node path
  2266. Node *node = p_node;
  2267. String path = root->get_path_to(node);
  2268. if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") {
  2269. if (node == AnimationPlayerEditor::singleton->get_player()) {
  2270. EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players."));
  2271. return;
  2272. }
  2273. _insert_animation_key(path, p_value);
  2274. return;
  2275. }
  2276. EditorHistory *history = EditorNode::get_singleton()->get_editor_history();
  2277. for (int i = 1; i < history->get_path_size(); i++) {
  2278. String prop = history->get_path_property(i);
  2279. ERR_FAIL_COND(prop == "");
  2280. path += ":" + prop;
  2281. }
  2282. path += ":" + p_property;
  2283. NodePath np = path;
  2284. //locate track
  2285. bool inserted = false;
  2286. for (int i = 0; i < animation->get_track_count(); i++) {
  2287. if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
  2288. if (animation->track_get_path(i) != np)
  2289. continue;
  2290. InsertData id;
  2291. id.path = np;
  2292. id.track_idx = i;
  2293. id.value = p_value;
  2294. id.type = Animation::TYPE_VALUE;
  2295. id.query = "property '" + p_property + "'";
  2296. id.advance = false;
  2297. //dialog insert
  2298. _query_insert(id);
  2299. inserted = true;
  2300. } else if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
  2301. Variant value;
  2302. if (animation->track_get_path(i) == np) {
  2303. value = p_value; //all good
  2304. } else {
  2305. String tpath = animation->track_get_path(i);
  2306. if (NodePath(tpath.get_basename()) == np) {
  2307. String subindex = tpath.get_extension();
  2308. value = p_value.get(subindex);
  2309. } else {
  2310. continue;
  2311. }
  2312. }
  2313. InsertData id;
  2314. id.path = animation->track_get_path(i);
  2315. id.track_idx = i;
  2316. id.value = value;
  2317. id.type = Animation::TYPE_BEZIER;
  2318. id.query = "property '" + p_property + "'";
  2319. id.advance = false;
  2320. //dialog insert
  2321. _query_insert(id);
  2322. inserted = true;
  2323. }
  2324. }
  2325. if (inserted || p_only_if_exists)
  2326. return;
  2327. InsertData id;
  2328. id.path = np;
  2329. id.track_idx = -1;
  2330. id.value = p_value;
  2331. id.type = Animation::TYPE_VALUE;
  2332. id.query = "property '" + p_property + "'";
  2333. id.advance = false;
  2334. //dialog insert
  2335. _query_insert(id);
  2336. }
  2337. void AnimationTrackEditor::insert_value_key(const String &p_property, const Variant &p_value, bool p_advance) {
  2338. EditorHistory *history = EditorNode::get_singleton()->get_editor_history();
  2339. ERR_FAIL_COND(!root);
  2340. //let's build a node path
  2341. ERR_FAIL_COND(history->get_path_size() == 0);
  2342. Object *obj = ObjectDB::get_instance(history->get_path_object(0));
  2343. ERR_FAIL_COND(!Object::cast_to<Node>(obj));
  2344. Node *node = Object::cast_to<Node>(obj);
  2345. String path = root->get_path_to(node);
  2346. if (Object::cast_to<AnimationPlayer>(node) && p_property == "current_animation") {
  2347. if (node == AnimationPlayerEditor::singleton->get_player()) {
  2348. EditorNode::get_singleton()->show_warning(TTR("AnimationPlayer can't animate itself, only other players."));
  2349. return;
  2350. }
  2351. _insert_animation_key(path, p_value);
  2352. return;
  2353. }
  2354. for (int i = 1; i < history->get_path_size(); i++) {
  2355. String prop = history->get_path_property(i);
  2356. ERR_FAIL_COND(prop == "");
  2357. path += ":" + prop;
  2358. }
  2359. path += ":" + p_property;
  2360. NodePath np = path;
  2361. //locate track
  2362. bool inserted = false;
  2363. for (int i = 0; i < animation->get_track_count(); i++) {
  2364. if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
  2365. if (animation->track_get_path(i) != np)
  2366. continue;
  2367. InsertData id;
  2368. id.path = np;
  2369. id.track_idx = i;
  2370. id.value = p_value;
  2371. id.type = Animation::TYPE_VALUE;
  2372. id.query = "property '" + p_property + "'";
  2373. id.advance = p_advance;
  2374. //dialog insert
  2375. _query_insert(id);
  2376. inserted = true;
  2377. } else if (animation->track_get_type(i) == Animation::TYPE_BEZIER) {
  2378. Variant value;
  2379. if (animation->track_get_path(i) == np) {
  2380. value = p_value; //all good
  2381. } else {
  2382. String tpath = animation->track_get_path(i);
  2383. if (NodePath(tpath.get_basename()) == np) {
  2384. String subindex = tpath.get_extension();
  2385. value = p_value.get(subindex);
  2386. } else {
  2387. continue;
  2388. }
  2389. }
  2390. InsertData id;
  2391. id.path = animation->track_get_path(i);
  2392. id.track_idx = i;
  2393. id.value = value;
  2394. id.type = Animation::TYPE_BEZIER;
  2395. id.query = "property '" + p_property + "'";
  2396. id.advance = p_advance;
  2397. //dialog insert
  2398. _query_insert(id);
  2399. inserted = true;
  2400. }
  2401. }
  2402. if (!inserted) {
  2403. InsertData id;
  2404. id.path = np;
  2405. id.track_idx = -1;
  2406. id.value = p_value;
  2407. id.type = Animation::TYPE_VALUE;
  2408. id.query = "property '" + p_property + "'";
  2409. id.advance = p_advance;
  2410. //dialog insert
  2411. _query_insert(id);
  2412. }
  2413. }
  2414. void AnimationTrackEditor::_confirm_insert_list() {
  2415. undo_redo->create_action(TTR("Anim Create & Insert"));
  2416. int last_track = animation->get_track_count();
  2417. while (insert_data.size()) {
  2418. last_track = _confirm_insert(insert_data.front()->get(), last_track, insert_confirm_bezier->is_pressed());
  2419. insert_data.pop_front();
  2420. }
  2421. undo_redo->commit_action();
  2422. }
  2423. PropertyInfo AnimationTrackEditor::_find_hint_for_track(int p_idx, NodePath &r_base_path, Variant *r_current_val) {
  2424. r_base_path = NodePath();
  2425. ERR_FAIL_COND_V(!animation.is_valid(), PropertyInfo());
  2426. ERR_FAIL_INDEX_V(p_idx, animation->get_track_count(), PropertyInfo());
  2427. if (!root) {
  2428. return PropertyInfo();
  2429. }
  2430. NodePath path = animation->track_get_path(p_idx);
  2431. if (!root->has_node_and_resource(path)) {
  2432. return PropertyInfo();
  2433. }
  2434. RES res;
  2435. Vector<StringName> leftover_path;
  2436. Node *node = root->get_node_and_resource(path, res, leftover_path, true);
  2437. if (node) {
  2438. r_base_path = node->get_path();
  2439. }
  2440. if (leftover_path.empty()) {
  2441. if (r_current_val) {
  2442. if (res.is_valid()) {
  2443. *r_current_val = res;
  2444. } else if (node) {
  2445. *r_current_val = node;
  2446. }
  2447. }
  2448. return PropertyInfo();
  2449. }
  2450. Variant property_info_base;
  2451. if (res.is_valid()) {
  2452. property_info_base = res;
  2453. if (r_current_val) {
  2454. *r_current_val = res->get_indexed(leftover_path);
  2455. }
  2456. } else if (node) {
  2457. property_info_base = node;
  2458. if (r_current_val) {
  2459. *r_current_val = node->get_indexed(leftover_path);
  2460. }
  2461. }
  2462. for (int i = 0; i < leftover_path.size() - 1; i++) {
  2463. property_info_base = property_info_base.get_named(leftover_path[i]);
  2464. }
  2465. List<PropertyInfo> pinfo;
  2466. property_info_base.get_property_list(&pinfo);
  2467. for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
  2468. if (E->get().name == leftover_path[leftover_path.size() - 1]) {
  2469. return E->get();
  2470. }
  2471. }
  2472. return PropertyInfo();
  2473. }
  2474. static Vector<String> _get_bezier_subindices_for_type(Variant::Type p_type, bool *r_valid = NULL) {
  2475. Vector<String> subindices;
  2476. if (r_valid) {
  2477. *r_valid = true;
  2478. }
  2479. switch (p_type) {
  2480. case Variant::INT: {
  2481. subindices.push_back("");
  2482. } break;
  2483. case Variant::REAL: {
  2484. subindices.push_back("");
  2485. } break;
  2486. case Variant::VECTOR2: {
  2487. subindices.push_back(":x");
  2488. subindices.push_back(":y");
  2489. } break;
  2490. case Variant::VECTOR3: {
  2491. subindices.push_back(":x");
  2492. subindices.push_back(":y");
  2493. subindices.push_back(":z");
  2494. } break;
  2495. case Variant::QUAT: {
  2496. subindices.push_back(":x");
  2497. subindices.push_back(":y");
  2498. subindices.push_back(":z");
  2499. subindices.push_back(":w");
  2500. } break;
  2501. case Variant::COLOR: {
  2502. subindices.push_back(":r");
  2503. subindices.push_back(":g");
  2504. subindices.push_back(":b");
  2505. subindices.push_back(":a");
  2506. } break;
  2507. case Variant::PLANE: {
  2508. subindices.push_back(":x");
  2509. subindices.push_back(":y");
  2510. subindices.push_back(":z");
  2511. subindices.push_back(":d");
  2512. } break;
  2513. default: {
  2514. if (r_valid) {
  2515. *r_valid = false;
  2516. }
  2517. }
  2518. }
  2519. return subindices;
  2520. }
  2521. int AnimationTrackEditor::_confirm_insert(InsertData p_id, int p_last_track, bool p_create_beziers) {
  2522. if (p_last_track == -1)
  2523. p_last_track = animation->get_track_count();
  2524. bool created = false;
  2525. if (p_id.track_idx < 0) {
  2526. if (p_create_beziers && (p_id.value.get_type() == Variant::VECTOR2 ||
  2527. p_id.value.get_type() == Variant::VECTOR3 ||
  2528. p_id.value.get_type() == Variant::QUAT ||
  2529. p_id.value.get_type() == Variant::COLOR ||
  2530. p_id.value.get_type() == Variant::PLANE)) {
  2531. Vector<String> subindices = _get_bezier_subindices_for_type(p_id.value.get_type());
  2532. for (int i = 0; i < subindices.size(); i++) {
  2533. InsertData id = p_id;
  2534. id.type = Animation::TYPE_BEZIER;
  2535. id.value = p_id.value.get(subindices[i].substr(1, subindices[i].length()));
  2536. id.path = String(p_id.path) + subindices[i];
  2537. _confirm_insert(id, p_last_track + i);
  2538. }
  2539. return p_last_track + subindices.size() - 1;
  2540. }
  2541. created = true;
  2542. undo_redo->create_action(TTR("Anim Insert Track & Key"));
  2543. Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
  2544. if (p_id.type == Animation::TYPE_VALUE || p_id.type == Animation::TYPE_BEZIER) {
  2545. //wants a new tack
  2546. {
  2547. //hack
  2548. NodePath np;
  2549. animation->add_track(p_id.type);
  2550. animation->track_set_path(animation->get_track_count() - 1, p_id.path);
  2551. PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
  2552. animation->remove_track(animation->get_track_count() - 1); //hack
  2553. if (h.type == Variant::REAL ||
  2554. h.type == Variant::VECTOR2 ||
  2555. h.type == Variant::RECT2 ||
  2556. h.type == Variant::VECTOR3 ||
  2557. h.type == Variant::AABB ||
  2558. h.type == Variant::QUAT ||
  2559. h.type == Variant::COLOR ||
  2560. h.type == Variant::PLANE ||
  2561. h.type == Variant::TRANSFORM2D ||
  2562. h.type == Variant::TRANSFORM) {
  2563. update_mode = Animation::UPDATE_CONTINUOUS;
  2564. }
  2565. if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) {
  2566. update_mode = Animation::UPDATE_TRIGGER;
  2567. }
  2568. }
  2569. }
  2570. p_id.track_idx = p_last_track;
  2571. undo_redo->add_do_method(animation.ptr(), "add_track", p_id.type);
  2572. undo_redo->add_do_method(animation.ptr(), "track_set_path", p_id.track_idx, p_id.path);
  2573. if (p_id.type == Animation::TYPE_VALUE)
  2574. undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", p_id.track_idx, update_mode);
  2575. } else {
  2576. undo_redo->create_action(TTR("Anim Insert Key"));
  2577. }
  2578. float time = timeline->get_play_position();
  2579. Variant value;
  2580. switch (p_id.type) {
  2581. case Animation::TYPE_VALUE: {
  2582. value = p_id.value;
  2583. } break;
  2584. case Animation::TYPE_TRANSFORM: {
  2585. Transform tr = p_id.value;
  2586. Dictionary d;
  2587. d["location"] = tr.origin;
  2588. d["scale"] = tr.basis.get_scale();
  2589. d["rotation"] = Quat(tr.basis); //.orthonormalized();
  2590. value = d;
  2591. } break;
  2592. case Animation::TYPE_BEZIER: {
  2593. Array array;
  2594. array.resize(5);
  2595. array[0] = p_id.value;
  2596. array[1] = -0.25;
  2597. array[2] = 0;
  2598. array[3] = 0.25;
  2599. array[4] = 0;
  2600. value = array;
  2601. } break;
  2602. case Animation::TYPE_ANIMATION: {
  2603. value = p_id.value;
  2604. } break;
  2605. default: {
  2606. }
  2607. }
  2608. undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_id.track_idx, time, value);
  2609. if (created) {
  2610. //just remove the track
  2611. undo_redo->add_undo_method(animation.ptr(), "remove_track", p_last_track);
  2612. p_last_track++;
  2613. } else {
  2614. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_id.track_idx, time);
  2615. int existing = animation->track_find_key(p_id.track_idx, time, true);
  2616. if (existing != -1) {
  2617. Variant v = animation->track_get_key_value(p_id.track_idx, existing);
  2618. float trans = animation->track_get_key_transition(p_id.track_idx, existing);
  2619. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", p_id.track_idx, time, v, trans);
  2620. }
  2621. }
  2622. undo_redo->commit_action();
  2623. return p_last_track;
  2624. }
  2625. void AnimationTrackEditor::show_select_node_warning(bool p_show) {
  2626. }
  2627. bool AnimationTrackEditor::is_key_selected(int p_track, int p_key) const {
  2628. SelectedKey sk;
  2629. sk.key = p_key;
  2630. sk.track = p_track;
  2631. return selection.has(sk);
  2632. }
  2633. bool AnimationTrackEditor::is_selection_active() const {
  2634. return selection.size();
  2635. }
  2636. void AnimationTrackEditor::_update_tracks() {
  2637. int selected = _get_track_selected();
  2638. while (track_vbox->get_child_count()) {
  2639. memdelete(track_vbox->get_child(0));
  2640. }
  2641. track_edits.clear();
  2642. groups.clear();
  2643. if (animation.is_null())
  2644. return;
  2645. Map<String, VBoxContainer *> group_sort;
  2646. bool use_grouping = !view_group->is_pressed();
  2647. bool use_filter = selected_filter->is_pressed();
  2648. for (int i = 0; i < animation->get_track_count(); i++) {
  2649. AnimationTrackEdit *track_edit = NULL;
  2650. //find hint and info for plugin
  2651. if (use_filter) {
  2652. NodePath path = animation->track_get_path(i);
  2653. if (root && root->has_node(path)) {
  2654. Node *node = root->get_node(path);
  2655. if (!node) {
  2656. continue; // no node, no filter
  2657. }
  2658. if (!EditorNode::get_singleton()->get_editor_selection()->is_selected(node)) {
  2659. continue; //skip track due to not selected
  2660. }
  2661. }
  2662. }
  2663. if (animation->track_get_type(i) == Animation::TYPE_VALUE) {
  2664. NodePath path = animation->track_get_path(i);
  2665. if (root && root->has_node_and_resource(path)) {
  2666. RES res;
  2667. NodePath base_path;
  2668. Vector<StringName> leftover_path;
  2669. Node *node = root->get_node_and_resource(path, res, leftover_path, true);
  2670. PropertyInfo pinfo = _find_hint_for_track(i, base_path);
  2671. Object *object = node;
  2672. if (res.is_valid()) {
  2673. object = res.ptr();
  2674. }
  2675. if (object && !leftover_path.empty()) {
  2676. if (pinfo.name.empty()) {
  2677. pinfo.name = leftover_path[leftover_path.size() - 1];
  2678. }
  2679. for (int j = 0; j < track_edit_plugins.size(); j++) {
  2680. track_edit = track_edit_plugins.write[j]->create_value_track_edit(object, pinfo.type, pinfo.name, pinfo.hint, pinfo.hint_string, pinfo.usage);
  2681. if (track_edit) {
  2682. break;
  2683. }
  2684. }
  2685. }
  2686. }
  2687. }
  2688. if (animation->track_get_type(i) == Animation::TYPE_AUDIO) {
  2689. for (int j = 0; j < track_edit_plugins.size(); j++) {
  2690. track_edit = track_edit_plugins.write[j]->create_audio_track_edit();
  2691. if (track_edit) {
  2692. break;
  2693. }
  2694. }
  2695. }
  2696. if (animation->track_get_type(i) == Animation::TYPE_ANIMATION) {
  2697. NodePath path = animation->track_get_path(i);
  2698. Node *node = NULL;
  2699. if (root && root->has_node(path)) {
  2700. node = root->get_node(path);
  2701. }
  2702. if (node && Object::cast_to<AnimationPlayer>(node)) {
  2703. for (int j = 0; j < track_edit_plugins.size(); j++) {
  2704. track_edit = track_edit_plugins.write[j]->create_animation_track_edit(node);
  2705. if (track_edit) {
  2706. break;
  2707. }
  2708. }
  2709. }
  2710. }
  2711. if (track_edit == NULL) {
  2712. //no valid plugin_found
  2713. track_edit = memnew(AnimationTrackEdit);
  2714. }
  2715. track_edits.push_back(track_edit);
  2716. if (use_grouping) {
  2717. String base_path = animation->track_get_path(i);
  2718. base_path = base_path.get_slice(":", 0); // remove subpath
  2719. if (!group_sort.has(base_path)) {
  2720. AnimationTrackEditGroup *g = memnew(AnimationTrackEditGroup);
  2721. Ref<Texture> icon = get_icon("Node", "EditorIcons");
  2722. String name = base_path;
  2723. String tooltip;
  2724. if (root) {
  2725. Node *n = root->get_node(base_path);
  2726. if (n) {
  2727. if (has_icon(n->get_class(), "EditorIcons")) {
  2728. icon = get_icon(n->get_class(), "EditorIcons");
  2729. }
  2730. name = n->get_name();
  2731. tooltip = root->get_path_to(n);
  2732. }
  2733. }
  2734. g->set_type_and_name(icon, name, animation->track_get_path(i));
  2735. g->set_root(root);
  2736. g->set_tooltip(tooltip);
  2737. g->set_timeline(timeline);
  2738. groups.push_back(g);
  2739. VBoxContainer *vb = memnew(VBoxContainer);
  2740. vb->add_constant_override("separation", 0);
  2741. vb->add_child(g);
  2742. track_vbox->add_child(vb);
  2743. group_sort[base_path] = vb;
  2744. }
  2745. track_edit->set_in_group(true);
  2746. group_sort[base_path]->add_child(track_edit);
  2747. } else {
  2748. track_edit->set_in_group(false);
  2749. track_vbox->add_child(track_edit);
  2750. }
  2751. track_edit->set_undo_redo(undo_redo);
  2752. track_edit->set_timeline(timeline);
  2753. track_edit->set_root(root);
  2754. track_edit->set_animation_and_track(animation, i);
  2755. track_edit->set_play_position(timeline->get_play_position());
  2756. track_edit->set_editor(this);
  2757. if (selected == i) {
  2758. track_edit->grab_focus();
  2759. }
  2760. track_edit->connect("timeline_changed", this, "_timeline_changed");
  2761. track_edit->connect("remove_request", this, "_track_remove_request", varray(), CONNECT_DEFERRED);
  2762. track_edit->connect("dropped", this, "_dropped_track", varray(), CONNECT_DEFERRED);
  2763. track_edit->connect("insert_key", this, "_insert_key_from_track", varray(i), CONNECT_DEFERRED);
  2764. track_edit->connect("select_key", this, "_key_selected", varray(i), CONNECT_DEFERRED);
  2765. track_edit->connect("deselect_key", this, "_key_deselected", varray(i), CONNECT_DEFERRED);
  2766. track_edit->connect("bezier_edit", this, "_bezier_edit", varray(i), CONNECT_DEFERRED);
  2767. track_edit->connect("clear_selection", this, "_clear_selection");
  2768. track_edit->connect("move_selection_begin", this, "_move_selection_begin");
  2769. track_edit->connect("move_selection", this, "_move_selection");
  2770. track_edit->connect("move_selection_commit", this, "_move_selection_commit");
  2771. track_edit->connect("move_selection_cancel", this, "_move_selection_cancel");
  2772. track_edit->connect("duplicate_request", this, "_edit_menu_pressed", varray(EDIT_DUPLICATE_SELECTION), CONNECT_DEFERRED);
  2773. track_edit->connect("duplicate_transpose_request", this, "_edit_menu_pressed", varray(EDIT_DUPLICATE_TRANSPOSED), CONNECT_DEFERRED);
  2774. track_edit->connect("delete_request", this, "_edit_menu_pressed", varray(EDIT_DELETE_SELECTION), CONNECT_DEFERRED);
  2775. }
  2776. }
  2777. void AnimationTrackEditor::_animation_changed() {
  2778. if (animation_changing_awaiting_update) {
  2779. return; //all will be updated, don't bother with anything
  2780. }
  2781. if (key_edit && key_edit->setting) {
  2782. //if editing a key, just update the edited track, makes refresh less costly
  2783. if (key_edit->track < track_edits.size()) {
  2784. if (animation->track_get_type(key_edit->track) == Animation::TYPE_BEZIER)
  2785. bezier_edit->update();
  2786. else
  2787. track_edits[key_edit->track]->update();
  2788. }
  2789. return;
  2790. }
  2791. animation_changing_awaiting_update = true;
  2792. call_deferred("_animation_update");
  2793. }
  2794. void AnimationTrackEditor::_snap_mode_changed(int p_mode) {
  2795. timeline->set_use_fps(p_mode == 1);
  2796. if (key_edit) {
  2797. key_edit->set_use_fps(p_mode == 1);
  2798. }
  2799. _update_step_spinbox();
  2800. }
  2801. void AnimationTrackEditor::_update_step_spinbox() {
  2802. if (!animation.is_valid()) {
  2803. return;
  2804. }
  2805. step->set_block_signals(true);
  2806. if (timeline->is_using_fps()) {
  2807. if (animation->get_step() == 0) {
  2808. step->set_value(0);
  2809. } else {
  2810. step->set_value(1.0 / animation->get_step());
  2811. }
  2812. } else {
  2813. step->set_value(animation->get_step());
  2814. }
  2815. step->set_block_signals(false);
  2816. }
  2817. void AnimationTrackEditor::_animation_update() {
  2818. timeline->update();
  2819. timeline->update_values();
  2820. bool same = true;
  2821. if (animation.is_null()) {
  2822. return;
  2823. }
  2824. if (track_edits.size() == animation->get_track_count()) {
  2825. //check tracks are the same
  2826. for (int i = 0; i < track_edits.size(); i++) {
  2827. if (track_edits[i]->get_path() != animation->track_get_path(i)) {
  2828. same = false;
  2829. break;
  2830. }
  2831. }
  2832. } else {
  2833. same = false;
  2834. }
  2835. if (same) {
  2836. for (int i = 0; i < track_edits.size(); i++) {
  2837. track_edits[i]->update();
  2838. }
  2839. for (int i = 0; i < groups.size(); i++) {
  2840. groups[i]->update();
  2841. }
  2842. } else {
  2843. _update_tracks();
  2844. }
  2845. bezier_edit->update();
  2846. _update_step_spinbox();
  2847. animation_changing_awaiting_update = false;
  2848. }
  2849. MenuButton *AnimationTrackEditor::get_edit_menu() {
  2850. return edit;
  2851. }
  2852. void AnimationTrackEditor::_notification(int p_what) {
  2853. if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) {
  2854. zoom_icon->set_texture(get_icon("Zoom", "EditorIcons"));
  2855. snap->set_icon(get_icon("Snap", "EditorIcons"));
  2856. view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
  2857. selected_filter->set_icon(get_icon("AnimationFilter", "EditorIcons"));
  2858. imported_anim_warning->set_icon(get_icon("NodeWarning", "EditorIcons"));
  2859. main_panel->add_style_override("panel", get_stylebox("bg", "Tree"));
  2860. }
  2861. if (p_what == NOTIFICATION_READY) {
  2862. EditorNode::get_singleton()->get_editor_selection()->connect("selection_changed", this, "_selection_changed");
  2863. }
  2864. if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
  2865. update_keying();
  2866. EditorNode::get_singleton()->update_keying();
  2867. emit_signal("keying_changed");
  2868. }
  2869. }
  2870. void AnimationTrackEditor::_update_scroll(double) {
  2871. for (int i = 0; i < track_edits.size(); i++) {
  2872. track_edits[i]->update();
  2873. }
  2874. for (int i = 0; i < groups.size(); i++) {
  2875. groups[i]->update();
  2876. }
  2877. }
  2878. void AnimationTrackEditor::_update_step(double p_new_step) {
  2879. undo_redo->create_action(TTR("Change Animation Step"));
  2880. float step_value = p_new_step;
  2881. if (timeline->is_using_fps()) {
  2882. if (step_value != 0.0) {
  2883. step_value = 1.0 / step_value;
  2884. }
  2885. }
  2886. undo_redo->add_do_method(animation.ptr(), "set_step", step_value);
  2887. undo_redo->add_undo_method(animation.ptr(), "set_step", animation->get_step());
  2888. step->set_block_signals(true);
  2889. undo_redo->commit_action();
  2890. step->set_block_signals(false);
  2891. emit_signal("animation_step_changed", step_value);
  2892. }
  2893. void AnimationTrackEditor::_update_length(double p_new_len) {
  2894. emit_signal("animation_len_changed", p_new_len);
  2895. }
  2896. void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) {
  2897. if (p_to_track >= track_edits.size()) {
  2898. p_to_track = track_edits.size() - 1;
  2899. }
  2900. if (p_from_track == p_to_track)
  2901. return;
  2902. _clear_selection();
  2903. undo_redo->create_action(TTR("Rearrange Tracks"));
  2904. undo_redo->add_do_method(animation.ptr(), "track_swap", p_from_track, p_to_track);
  2905. undo_redo->add_undo_method(animation.ptr(), "track_swap", p_to_track, p_from_track);
  2906. undo_redo->commit_action();
  2907. }
  2908. void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
  2909. ERR_FAIL_COND(!root);
  2910. Node *node = get_node(p_path);
  2911. ERR_FAIL_COND(!node);
  2912. NodePath path_to = root->get_path_to(node);
  2913. if (adding_track_type == Animation::TYPE_TRANSFORM && !node->is_class("Spatial")) {
  2914. EditorNode::get_singleton()->show_warning(TTR("Transform tracks only apply to Spatial-based nodes."));
  2915. return;
  2916. }
  2917. switch (adding_track_type) {
  2918. case Animation::TYPE_VALUE: {
  2919. adding_track_path = path_to;
  2920. prop_selector->set_type_filter(Vector<Variant::Type>());
  2921. prop_selector->select_property_from_instance(node);
  2922. } break;
  2923. case Animation::TYPE_TRANSFORM:
  2924. case Animation::TYPE_METHOD: {
  2925. undo_redo->create_action(TTR("Add Track"));
  2926. undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
  2927. undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
  2928. undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
  2929. undo_redo->commit_action();
  2930. } break;
  2931. case Animation::TYPE_BEZIER: {
  2932. Vector<Variant::Type> filter;
  2933. filter.push_back(Variant::INT);
  2934. filter.push_back(Variant::REAL);
  2935. filter.push_back(Variant::VECTOR2);
  2936. filter.push_back(Variant::VECTOR3);
  2937. filter.push_back(Variant::QUAT);
  2938. filter.push_back(Variant::PLANE);
  2939. filter.push_back(Variant::COLOR);
  2940. adding_track_path = path_to;
  2941. prop_selector->set_type_filter(filter);
  2942. prop_selector->select_property_from_instance(node);
  2943. } break;
  2944. case Animation::TYPE_AUDIO: {
  2945. if (!node->is_class("AudioStreamPlayer") && !node->is_class("AudioStreamPlayer2D") && !node->is_class("AudioStreamPlayer3D")) {
  2946. EditorNode::get_singleton()->show_warning(TTR("Audio tracks can only point to nodes of type:\n-AudioStreamPlayer\n-AudioStreamPlayer2D\n-AudioStreamPlayer3D"));
  2947. return;
  2948. }
  2949. undo_redo->create_action(TTR("Add Track"));
  2950. undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
  2951. undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
  2952. undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
  2953. undo_redo->commit_action();
  2954. } break;
  2955. case Animation::TYPE_ANIMATION: {
  2956. if (!node->is_class("AnimationPlayer")) {
  2957. EditorNode::get_singleton()->show_warning(TTR("Animation tracks can only point to AnimationPlayer nodes."));
  2958. return;
  2959. }
  2960. if (node == AnimationPlayerEditor::singleton->get_player()) {
  2961. EditorNode::get_singleton()->show_warning(TTR("An animation player can't animate itself, only other players."));
  2962. return;
  2963. }
  2964. undo_redo->create_action(TTR("Add Track"));
  2965. undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
  2966. undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
  2967. undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
  2968. undo_redo->commit_action();
  2969. } break;
  2970. }
  2971. }
  2972. void AnimationTrackEditor::_add_track(int p_type) {
  2973. if (!root) {
  2974. EditorNode::get_singleton()->show_warning(TTR("Not possible to add a new track without a root"));
  2975. return;
  2976. }
  2977. adding_track_type = p_type;
  2978. pick_track->popup_centered_ratio();
  2979. }
  2980. void AnimationTrackEditor::_new_track_property_selected(String p_name) {
  2981. String full_path = String(adding_track_path) + ":" + p_name;
  2982. if (adding_track_type == Animation::TYPE_VALUE) {
  2983. Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
  2984. {
  2985. //hack
  2986. NodePath np;
  2987. animation->add_track(Animation::TYPE_VALUE);
  2988. animation->track_set_path(animation->get_track_count() - 1, full_path);
  2989. PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
  2990. animation->remove_track(animation->get_track_count() - 1); //hack
  2991. if (h.type == Variant::REAL ||
  2992. h.type == Variant::VECTOR2 ||
  2993. h.type == Variant::RECT2 ||
  2994. h.type == Variant::VECTOR3 ||
  2995. h.type == Variant::AABB ||
  2996. h.type == Variant::QUAT ||
  2997. h.type == Variant::COLOR ||
  2998. h.type == Variant::PLANE ||
  2999. h.type == Variant::TRANSFORM2D ||
  3000. h.type == Variant::TRANSFORM) {
  3001. update_mode = Animation::UPDATE_CONTINUOUS;
  3002. }
  3003. if (h.usage & PROPERTY_USAGE_ANIMATE_AS_TRIGGER) {
  3004. update_mode = Animation::UPDATE_TRIGGER;
  3005. }
  3006. }
  3007. undo_redo->create_action(TTR("Add Track"));
  3008. undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
  3009. undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), full_path);
  3010. undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", animation->get_track_count(), update_mode);
  3011. undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
  3012. undo_redo->commit_action();
  3013. } else {
  3014. Vector<String> subindices;
  3015. {
  3016. //hack
  3017. NodePath np;
  3018. animation->add_track(Animation::TYPE_VALUE);
  3019. animation->track_set_path(animation->get_track_count() - 1, full_path);
  3020. PropertyInfo h = _find_hint_for_track(animation->get_track_count() - 1, np);
  3021. animation->remove_track(animation->get_track_count() - 1); //hack
  3022. bool valid;
  3023. subindices = _get_bezier_subindices_for_type(h.type, &valid);
  3024. if (!valid) {
  3025. EditorNode::get_singleton()->show_warning("Invalid track for Bezier (no suitable sub-properties)");
  3026. return;
  3027. }
  3028. }
  3029. undo_redo->create_action(TTR("Add Bezier Track"));
  3030. int base_track = animation->get_track_count();
  3031. for (int i = 0; i < subindices.size(); i++) {
  3032. undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
  3033. undo_redo->add_do_method(animation.ptr(), "track_set_path", base_track + i, full_path + subindices[i]);
  3034. undo_redo->add_undo_method(animation.ptr(), "remove_track", base_track + i);
  3035. }
  3036. undo_redo->commit_action();
  3037. }
  3038. }
  3039. void AnimationTrackEditor::_timeline_value_changed(double) {
  3040. timeline->update_play_position();
  3041. for (int i = 0; i < track_edits.size(); i++) {
  3042. track_edits[i]->update();
  3043. track_edits[i]->update_play_position();
  3044. }
  3045. for (int i = 0; i < groups.size(); i++) {
  3046. groups[i]->update();
  3047. }
  3048. bezier_edit->update();
  3049. bezier_edit->update_play_position();
  3050. }
  3051. int AnimationTrackEditor::_get_track_selected() {
  3052. for (int i = 0; i < track_edits.size(); i++) {
  3053. if (track_edits[i]->has_focus())
  3054. return i;
  3055. }
  3056. return -1;
  3057. }
  3058. void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
  3059. ERR_FAIL_INDEX(p_track, animation->get_track_count());
  3060. if (snap->is_pressed() && step->get_value() != 0) {
  3061. p_ofs = snap_time(p_ofs);
  3062. }
  3063. while (animation->track_find_key(p_track, p_ofs, true) != -1) { //make sure insertion point is valid
  3064. p_ofs += 0.001;
  3065. }
  3066. switch (animation->track_get_type(p_track)) {
  3067. case Animation::TYPE_TRANSFORM: {
  3068. if (!root->has_node(animation->track_get_path(p_track))) {
  3069. EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a key."));
  3070. return;
  3071. }
  3072. Spatial *base = Object::cast_to<Spatial>(root->get_node(animation->track_get_path(p_track)));
  3073. if (!base) {
  3074. EditorNode::get_singleton()->show_warning(TTR("Track is not of type Spatial, can't insert key"));
  3075. return;
  3076. }
  3077. Transform xf = base->get_transform();
  3078. Vector3 loc = xf.get_origin();
  3079. Vector3 scale = xf.basis.get_scale_local();
  3080. Quat rot = xf.basis;
  3081. undo_redo->create_action(TTR("Add Transform Track Key"));
  3082. undo_redo->add_do_method(animation.ptr(), "transform_track_insert_key", p_track, p_ofs, loc, rot, scale);
  3083. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
  3084. undo_redo->commit_action();
  3085. } break;
  3086. case Animation::TYPE_VALUE: {
  3087. NodePath bp;
  3088. Variant value;
  3089. _find_hint_for_track(p_track, bp, &value);
  3090. undo_redo->create_action(TTR("Add Track Key"));
  3091. undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, value);
  3092. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
  3093. undo_redo->commit_action();
  3094. } break;
  3095. case Animation::TYPE_METHOD: {
  3096. if (!root->has_node(animation->track_get_path(p_track))) {
  3097. EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a method key."));
  3098. return;
  3099. }
  3100. Node *base = root->get_node(animation->track_get_path(p_track));
  3101. method_selector->select_method_from_instance(base);
  3102. insert_key_from_track_call_ofs = p_ofs;
  3103. insert_key_from_track_call_track = p_track;
  3104. } break;
  3105. case Animation::TYPE_BEZIER: {
  3106. NodePath bp;
  3107. Variant value;
  3108. _find_hint_for_track(p_track, bp, &value);
  3109. Array arr;
  3110. arr.resize(5);
  3111. arr[0] = value;
  3112. arr[1] = -0.25;
  3113. arr[2] = 0;
  3114. arr[3] = 0.25;
  3115. arr[4] = 0;
  3116. undo_redo->create_action(TTR("Add Track Key"));
  3117. undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, arr);
  3118. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
  3119. undo_redo->commit_action();
  3120. } break;
  3121. case Animation::TYPE_AUDIO: {
  3122. Dictionary ak;
  3123. ak["stream"] = RES();
  3124. ak["start_offset"] = 0;
  3125. ak["end_offset"] = 0;
  3126. undo_redo->create_action(TTR("Add Track Key"));
  3127. undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, ak);
  3128. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
  3129. undo_redo->commit_action();
  3130. } break;
  3131. case Animation::TYPE_ANIMATION: {
  3132. StringName anim = "[stop]";
  3133. undo_redo->create_action(TTR("Add Track Key"));
  3134. undo_redo->add_do_method(animation.ptr(), "track_insert_key", p_track, p_ofs, anim);
  3135. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", p_track, p_ofs);
  3136. undo_redo->commit_action();
  3137. } break;
  3138. }
  3139. }
  3140. void AnimationTrackEditor::_add_method_key(const String &p_method) {
  3141. if (!root->has_node(animation->track_get_path(insert_key_from_track_call_track))) {
  3142. EditorNode::get_singleton()->show_warning(TTR("Track path is invalid, so can't add a method key."));
  3143. return;
  3144. }
  3145. Node *base = root->get_node(animation->track_get_path(insert_key_from_track_call_track));
  3146. List<MethodInfo> minfo;
  3147. base->get_method_list(&minfo);
  3148. for (List<MethodInfo>::Element *E = minfo.front(); E; E = E->next()) {
  3149. if (E->get().name == p_method) {
  3150. Dictionary d;
  3151. d["method"] = p_method;
  3152. Array params;
  3153. int first_defarg = E->get().arguments.size() - E->get().default_arguments.size();
  3154. for (int i = 0; i < E->get().arguments.size(); i++) {
  3155. if (i >= first_defarg) {
  3156. Variant arg = E->get().default_arguments[i - first_defarg];
  3157. params.push_back(arg);
  3158. } else {
  3159. Variant::CallError ce;
  3160. Variant arg = Variant::construct(E->get().arguments[i].type, NULL, 0, ce);
  3161. params.push_back(arg);
  3162. }
  3163. }
  3164. d["args"] = params;
  3165. undo_redo->create_action(TTR("Add Method Track Key"));
  3166. undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d);
  3167. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
  3168. undo_redo->commit_action();
  3169. return;
  3170. }
  3171. }
  3172. EditorNode::get_singleton()->show_warning(TTR("Method not found in object: ") + p_method);
  3173. }
  3174. void AnimationTrackEditor::_key_selected(int p_key, bool p_single, int p_track) {
  3175. ERR_FAIL_INDEX(p_track, animation->get_track_count());
  3176. ERR_FAIL_INDEX(p_key, animation->track_get_key_count(p_track));
  3177. SelectedKey sk;
  3178. sk.key = p_key;
  3179. sk.track = p_track;
  3180. if (p_single) {
  3181. _clear_selection();
  3182. }
  3183. KeyInfo ki;
  3184. ki.pos = animation->track_get_key_time(p_track, p_key);
  3185. selection[sk] = ki;
  3186. for (int i = 0; i < track_edits.size(); i++) {
  3187. track_edits[i]->update();
  3188. }
  3189. _update_key_edit();
  3190. }
  3191. void AnimationTrackEditor::_key_deselected(int p_key, int p_track) {
  3192. ERR_FAIL_INDEX(p_track, animation->get_track_count());
  3193. ERR_FAIL_INDEX(p_key, animation->track_get_key_count(p_track));
  3194. SelectedKey sk;
  3195. sk.key = p_key;
  3196. sk.track = p_track;
  3197. selection.erase(sk);
  3198. for (int i = 0; i < track_edits.size(); i++) {
  3199. track_edits[i]->update();
  3200. }
  3201. _update_key_edit();
  3202. }
  3203. void AnimationTrackEditor::_move_selection_begin() {
  3204. moving_selection = true;
  3205. moving_selection_offset = 0;
  3206. }
  3207. void AnimationTrackEditor::_move_selection(float p_offset) {
  3208. moving_selection_offset = p_offset;
  3209. for (int i = 0; i < track_edits.size(); i++) {
  3210. track_edits[i]->update();
  3211. }
  3212. }
  3213. struct _AnimMoveRestore {
  3214. int track;
  3215. float time;
  3216. Variant key;
  3217. float transition;
  3218. };
  3219. //used for undo/redo
  3220. void AnimationTrackEditor::_clear_key_edit() {
  3221. if (key_edit) {
  3222. #if 0
  3223. // going back seems like the most comfortable thing to do, but it results
  3224. // in weird behaviors and crashes, because going back to animation editor
  3225. // triggers the editor setting up again itself
  3226. bool go_back = false;
  3227. if (EditorNode::get_singleton()->get_inspector()->get_edited_object() == key_edit) {
  3228. EditorNode::get_singleton()->push_item(NULL);
  3229. go_back = true;
  3230. }
  3231. memdelete(key_edit);
  3232. key_edit = NULL;
  3233. if (go_back) {
  3234. EditorNode::get_singleton()->get_inspector_dock()->go_back();
  3235. }
  3236. #else
  3237. //if key edit is the object being inspected, remove it first
  3238. if (EditorNode::get_singleton()->get_inspector()->get_edited_object() == key_edit) {
  3239. EditorNode::get_singleton()->push_item(NULL);
  3240. }
  3241. //then actually delete it
  3242. memdelete(key_edit);
  3243. key_edit = NULL;
  3244. #endif
  3245. }
  3246. }
  3247. void AnimationTrackEditor::_clear_selection() {
  3248. selection.clear();
  3249. for (int i = 0; i < track_edits.size(); i++) {
  3250. track_edits[i]->update();
  3251. }
  3252. _clear_key_edit();
  3253. }
  3254. void AnimationTrackEditor::_update_key_edit() {
  3255. _clear_key_edit();
  3256. if (!animation.is_valid())
  3257. return;
  3258. if (selection.size() != 1) {
  3259. return;
  3260. }
  3261. key_edit = memnew(AnimationTrackKeyEdit);
  3262. key_edit->animation = animation;
  3263. key_edit->track = selection.front()->key().track;
  3264. key_edit->use_fps = timeline->is_using_fps();
  3265. float ofs = animation->track_get_key_time(key_edit->track, selection.front()->key().key);
  3266. key_edit->key_ofs = ofs;
  3267. key_edit->root_path = root;
  3268. NodePath np;
  3269. key_edit->hint = _find_hint_for_track(key_edit->track, np);
  3270. key_edit->undo_redo = undo_redo;
  3271. key_edit->base = np;
  3272. EditorNode::get_singleton()->push_item(key_edit);
  3273. }
  3274. void AnimationTrackEditor::_clear_selection_for_anim(const Ref<Animation> &p_anim) {
  3275. if (!(animation == p_anim))
  3276. return;
  3277. //selection.clear();
  3278. _clear_selection();
  3279. }
  3280. void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_track, float p_pos) {
  3281. if (!(animation == p_anim))
  3282. return;
  3283. int idx = animation->track_find_key(p_track, p_pos, true);
  3284. ERR_FAIL_COND(idx < 0);
  3285. SelectedKey sk;
  3286. sk.track = p_track;
  3287. sk.key = idx;
  3288. KeyInfo ki;
  3289. ki.pos = p_pos;
  3290. selection.insert(sk, ki);
  3291. }
  3292. void AnimationTrackEditor::_move_selection_commit() {
  3293. undo_redo->create_action(TTR("Anim Move Keys"));
  3294. List<_AnimMoveRestore> to_restore;
  3295. float motion = moving_selection_offset;
  3296. // 1-remove the keys
  3297. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3298. undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
  3299. }
  3300. // 2- remove overlapped keys
  3301. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3302. float newtime = snap_time(E->get().pos + motion);
  3303. int idx = animation->track_find_key(E->key().track, newtime, true);
  3304. if (idx == -1)
  3305. continue;
  3306. SelectedKey sk;
  3307. sk.key = idx;
  3308. sk.track = E->key().track;
  3309. if (selection.has(sk))
  3310. continue; //already in selection, don't save
  3311. undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newtime);
  3312. _AnimMoveRestore amr;
  3313. amr.key = animation->track_get_key_value(E->key().track, idx);
  3314. amr.track = E->key().track;
  3315. amr.time = newtime;
  3316. amr.transition = animation->track_get_key_transition(E->key().track, idx);
  3317. to_restore.push_back(amr);
  3318. }
  3319. // 3-move the keys (re insert them)
  3320. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3321. float newpos = snap_time(E->get().pos + motion);
  3322. /*
  3323. if (newpos<0)
  3324. continue; //no add at the beginning
  3325. */
  3326. undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
  3327. }
  3328. // 4-(undo) remove inserted keys
  3329. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3330. float newpos = snap_time(E->get().pos + motion);
  3331. /*
  3332. if (newpos<0)
  3333. continue; //no remove what no inserted
  3334. */
  3335. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newpos);
  3336. }
  3337. // 5-(undo) reinsert keys
  3338. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3339. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
  3340. }
  3341. // 6-(undo) reinsert overlapped keys
  3342. for (List<_AnimMoveRestore>::Element *E = to_restore.front(); E; E = E->next()) {
  3343. _AnimMoveRestore &amr = E->get();
  3344. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
  3345. }
  3346. undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
  3347. undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
  3348. // 7-reselect
  3349. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3350. float oldpos = E->get().pos;
  3351. float newpos = snap_time(oldpos + motion);
  3352. //if (newpos>=0)
  3353. undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos);
  3354. undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
  3355. }
  3356. undo_redo->commit_action();
  3357. moving_selection = false;
  3358. for (int i = 0; i < track_edits.size(); i++) {
  3359. track_edits[i]->update();
  3360. }
  3361. _update_key_edit();
  3362. }
  3363. void AnimationTrackEditor::_move_selection_cancel() {
  3364. moving_selection = false;
  3365. for (int i = 0; i < track_edits.size(); i++) {
  3366. track_edits[i]->update();
  3367. }
  3368. }
  3369. bool AnimationTrackEditor::is_moving_selection() const {
  3370. return moving_selection;
  3371. }
  3372. float AnimationTrackEditor::get_moving_selection_offset() const {
  3373. return moving_selection_offset;
  3374. }
  3375. void AnimationTrackEditor::_box_selection_draw() {
  3376. Color color = get_color("accent_color", "Editor");
  3377. color.a = 0.2;
  3378. Rect2 rect = Rect2(Point2(), box_selection->get_size());
  3379. box_selection->draw_rect(rect, color);
  3380. }
  3381. void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) {
  3382. Ref<InputEventMouseButton> mb = p_event;
  3383. if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_DOWN) {
  3384. timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() * 1.05);
  3385. scroll->accept_event();
  3386. }
  3387. if (mb.is_valid() && mb->is_pressed() && mb->get_command() && mb->get_button_index() == BUTTON_WHEEL_UP) {
  3388. timeline->get_zoom()->set_value(timeline->get_zoom()->get_value() / 1.05);
  3389. scroll->accept_event();
  3390. }
  3391. if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) {
  3392. if (mb->is_pressed()) {
  3393. box_selecting = true;
  3394. box_selecting_from = scroll->get_global_transform().xform(mb->get_position());
  3395. box_select_rect = Rect2();
  3396. } else if (box_selecting) {
  3397. if (box_selection->is_visible_in_tree()) {
  3398. //only if moved
  3399. for (int i = 0; i < track_edits.size(); i++) {
  3400. Rect2 local_rect = box_select_rect;
  3401. local_rect.position -= track_edits[i]->get_global_position();
  3402. track_edits[i]->append_to_selection(local_rect);
  3403. }
  3404. if (_get_track_selected() == -1 && track_edits.size() > 0) { //minimal hack to make shortcuts work
  3405. track_edits[track_edits.size() - 1]->grab_focus();
  3406. }
  3407. } else {
  3408. _clear_selection(); //clear it
  3409. }
  3410. box_selection->hide();
  3411. box_selecting = false;
  3412. }
  3413. }
  3414. Ref<InputEventMouseMotion> mm = p_event;
  3415. if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_MIDDLE) {
  3416. timeline->set_value(timeline->get_value() - mm->get_relative().x / timeline->get_zoom_scale());
  3417. }
  3418. if (mm.is_valid() && box_selecting) {
  3419. if (!(mm->get_button_mask() & BUTTON_MASK_LEFT)) {
  3420. //no longer
  3421. box_selection->hide();
  3422. box_selecting = false;
  3423. return;
  3424. }
  3425. if (!box_selection->is_visible_in_tree()) {
  3426. if (!mm->get_shift()) {
  3427. _clear_selection(); //only append if shift is pressed
  3428. }
  3429. box_selection->show();
  3430. }
  3431. Vector2 from = box_selecting_from;
  3432. Vector2 to = scroll->get_global_transform().xform(mm->get_position());
  3433. if (from.x > to.x) {
  3434. SWAP(from.x, to.x);
  3435. }
  3436. if (from.y > to.y) {
  3437. SWAP(from.y, to.y);
  3438. }
  3439. Rect2 rect(from, to - from);
  3440. Rect2 scroll_rect = Rect2(scroll->get_global_position(), scroll->get_size());
  3441. rect = scroll_rect.clip(rect);
  3442. box_selection->set_position(rect.position);
  3443. box_selection->set_size(rect.size);
  3444. box_select_rect = rect;
  3445. if (get_local_mouse_position().y < 0) {
  3446. //avoid box selection from going up and lose focus to viewport
  3447. warp_mouse(Vector2(mm->get_position().x, 0));
  3448. }
  3449. }
  3450. }
  3451. void AnimationTrackEditor::_cancel_bezier_edit() {
  3452. bezier_edit->hide();
  3453. scroll->show();
  3454. }
  3455. void AnimationTrackEditor::_bezier_edit(int p_for_track) {
  3456. _clear_selection(); //bezier probably wants to use a separate selection mode
  3457. bezier_edit->set_root(root);
  3458. bezier_edit->set_animation_and_track(animation, p_for_track);
  3459. scroll->hide();
  3460. bezier_edit->show();
  3461. //search everything within the track and curve- edit it
  3462. }
  3463. void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
  3464. //duplicait!
  3465. if (selection.size() && animation.is_valid() && (!transpose || (_get_track_selected() >= 0 && _get_track_selected() < animation->get_track_count()))) {
  3466. int top_track = 0x7FFFFFFF;
  3467. float top_time = 1e10;
  3468. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3469. const SelectedKey &sk = E->key();
  3470. float t = animation->track_get_key_time(sk.track, sk.key);
  3471. if (t < top_time)
  3472. top_time = t;
  3473. if (sk.track < top_track)
  3474. top_track = sk.track;
  3475. }
  3476. ERR_FAIL_COND(top_track == 0x7FFFFFFF || top_time == 1e10);
  3477. //
  3478. int start_track = transpose ? _get_track_selected() : top_track;
  3479. undo_redo->create_action(TTR("Anim Duplicate Keys"));
  3480. List<Pair<int, float> > new_selection_values;
  3481. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3482. const SelectedKey &sk = E->key();
  3483. float t = animation->track_get_key_time(sk.track, sk.key);
  3484. float dst_time = t + (timeline->get_play_position() - top_time);
  3485. int dst_track = sk.track + (start_track - top_track);
  3486. if (dst_track < 0 || dst_track >= animation->get_track_count())
  3487. continue;
  3488. if (animation->track_get_type(dst_track) != animation->track_get_type(sk.track))
  3489. continue;
  3490. int existing_idx = animation->track_find_key(dst_track, dst_time, true);
  3491. undo_redo->add_do_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
  3492. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", dst_track, dst_time);
  3493. Pair<int, float> p;
  3494. p.first = dst_track;
  3495. p.second = dst_time;
  3496. new_selection_values.push_back(p);
  3497. if (existing_idx != -1) {
  3498. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", dst_track, dst_time, animation->track_get_key_value(dst_track, existing_idx), animation->track_get_key_transition(dst_track, existing_idx));
  3499. }
  3500. }
  3501. undo_redo->commit_action();
  3502. //reselect duplicated
  3503. Map<SelectedKey, KeyInfo> new_selection;
  3504. for (List<Pair<int, float> >::Element *E = new_selection_values.front(); E; E = E->next()) {
  3505. int track = E->get().first;
  3506. float time = E->get().second;
  3507. int existing_idx = animation->track_find_key(track, time, true);
  3508. if (existing_idx == -1)
  3509. continue;
  3510. SelectedKey sk2;
  3511. sk2.track = track;
  3512. sk2.key = existing_idx;
  3513. KeyInfo ki;
  3514. ki.pos = time;
  3515. new_selection[sk2] = ki;
  3516. }
  3517. selection = new_selection;
  3518. _update_tracks();
  3519. _update_key_edit();
  3520. }
  3521. }
  3522. void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
  3523. last_menu_track_opt = p_option;
  3524. switch (p_option) {
  3525. case EDIT_COPY_TRACKS: {
  3526. track_copy_select->clear();
  3527. TreeItem *troot = track_copy_select->create_item();
  3528. for (int i = 0; i < animation->get_track_count(); i++) {
  3529. NodePath path = animation->track_get_path(i);
  3530. Node *node = NULL;
  3531. if (root && root->has_node(path)) {
  3532. node = root->get_node(path);
  3533. }
  3534. String text;
  3535. Ref<Texture> icon = get_icon("Node", "EditorIcons");
  3536. if (node) {
  3537. if (has_icon(node->get_class(), "EditorIcons")) {
  3538. icon = get_icon(node->get_class(), "EditorIcons");
  3539. }
  3540. text = node->get_name();
  3541. Vector<StringName> sn = path.get_subnames();
  3542. for (int j = 0; j < sn.size(); j++) {
  3543. text += ".";
  3544. text += sn[j];
  3545. }
  3546. path = NodePath(node->get_path().get_names(), path.get_subnames(), true); //store full path instead for copying
  3547. } else {
  3548. text = path;
  3549. int sep = text.find(":");
  3550. if (sep != -1) {
  3551. text = text.substr(sep + 1, text.length());
  3552. }
  3553. }
  3554. switch (animation->track_get_type(i)) {
  3555. case Animation::TYPE_TRANSFORM: text += " (Transform)"; break;
  3556. case Animation::TYPE_METHOD: text += " (Methods)"; break;
  3557. case Animation::TYPE_BEZIER: text += " (Bezier)"; break;
  3558. case Animation::TYPE_AUDIO: text += " (Audio)"; break;
  3559. default: {
  3560. };
  3561. }
  3562. TreeItem *it = track_copy_select->create_item(troot);
  3563. it->set_editable(0, true);
  3564. it->set_selectable(0, true);
  3565. it->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  3566. it->set_icon(0, icon);
  3567. it->set_text(0, text);
  3568. Dictionary md;
  3569. md["track_idx"] = i;
  3570. md["path"] = path;
  3571. it->set_metadata(0, md);
  3572. }
  3573. track_copy_dialog->popup_centered_minsize(Size2(300, 500) * EDSCALE);
  3574. } break;
  3575. case EDIT_COPY_TRACKS_CONFIRM: {
  3576. track_clipboard.clear();
  3577. TreeItem *root = track_copy_select->get_root();
  3578. if (root) {
  3579. TreeItem *it = root->get_children();
  3580. while (it) {
  3581. Dictionary md = it->get_metadata(0);
  3582. int idx = md["track_idx"];
  3583. if (it->is_checked(0) && idx >= 0 && idx < animation->get_track_count()) {
  3584. TrackClipboard tc;
  3585. tc.base_path = animation->track_get_path(idx);
  3586. tc.full_path = md["path"];
  3587. tc.track_type = animation->track_get_type(idx);
  3588. tc.interp_type = animation->track_get_interpolation_type(idx);
  3589. if (tc.track_type == Animation::TYPE_VALUE) {
  3590. tc.update_mode = animation->value_track_get_update_mode(idx);
  3591. }
  3592. tc.loop_wrap = animation->track_get_interpolation_loop_wrap(idx);
  3593. tc.enabled = animation->track_is_enabled(idx);
  3594. for (int i = 0; i < animation->track_get_key_count(idx); i++) {
  3595. TrackClipboard::Key k;
  3596. k.time = animation->track_get_key_time(idx, i);
  3597. k.value = animation->track_get_key_value(idx, i);
  3598. k.transition = animation->track_get_key_transition(idx, i);
  3599. tc.keys.push_back(k);
  3600. }
  3601. track_clipboard.push_back(tc);
  3602. }
  3603. it = it->get_next();
  3604. }
  3605. }
  3606. } break;
  3607. case EDIT_PASTE_TRACKS: {
  3608. if (track_clipboard.size() == 0) {
  3609. EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty"));
  3610. break;
  3611. }
  3612. int base_track = animation->get_track_count();
  3613. undo_redo->create_action(TTR("Paste Tracks"));
  3614. for (int i = 0; i < track_clipboard.size(); i++) {
  3615. undo_redo->add_do_method(animation.ptr(), "add_track", track_clipboard[i].track_type);
  3616. Node *exists = NULL;
  3617. NodePath path = track_clipboard[i].base_path;
  3618. if (root) {
  3619. NodePath np = track_clipboard[i].full_path;
  3620. exists = root->get_node(np);
  3621. if (exists) {
  3622. path = NodePath(root->get_path_to(exists).get_names(), track_clipboard[i].full_path.get_subnames(), false);
  3623. }
  3624. }
  3625. undo_redo->add_do_method(animation.ptr(), "track_set_path", base_track, path);
  3626. undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", base_track, track_clipboard[i].interp_type);
  3627. undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", base_track, track_clipboard[i].loop_wrap);
  3628. undo_redo->add_do_method(animation.ptr(), "track_set_enabled", base_track, track_clipboard[i].enabled);
  3629. if (track_clipboard[i].track_type == Animation::TYPE_VALUE) {
  3630. undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", base_track, track_clipboard[i].update_mode);
  3631. }
  3632. for (int j = 0; j < track_clipboard[i].keys.size(); j++) {
  3633. undo_redo->add_do_method(animation.ptr(), "track_insert_key", base_track, track_clipboard[i].keys[j].time, track_clipboard[i].keys[j].value, track_clipboard[i].keys[j].transition);
  3634. }
  3635. undo_redo->add_undo_method(animation.ptr(), "remove_track", animation->get_track_count());
  3636. base_track++;
  3637. }
  3638. undo_redo->commit_action();
  3639. } break;
  3640. case EDIT_SCALE_SELECTION:
  3641. case EDIT_SCALE_FROM_CURSOR: {
  3642. scale_dialog->popup_centered(Size2(200, 100) * EDSCALE);
  3643. } break;
  3644. case EDIT_SCALE_CONFIRM: {
  3645. if (selection.empty())
  3646. return;
  3647. float from_t = 1e20;
  3648. float to_t = -1e20;
  3649. float len = -1e20;
  3650. float pivot = 0;
  3651. for (Map<SelectedKey, KeyInfo>::Element *E = selection.front(); E; E = E->next()) {
  3652. float t = animation->track_get_key_time(E->key().track, E->key().key);
  3653. if (t < from_t)
  3654. from_t = t;
  3655. if (t > to_t)
  3656. to_t = t;
  3657. }
  3658. len = to_t - from_t;
  3659. if (last_menu_track_opt == EDIT_SCALE_FROM_CURSOR) {
  3660. pivot = timeline->get_play_position();
  3661. } else {
  3662. pivot = from_t;
  3663. }
  3664. float s = scale->get_value();
  3665. if (s == 0) {
  3666. ERR_PRINT("Can't scale to 0");
  3667. }
  3668. undo_redo->create_action(TTR("Anim Scale Keys"));
  3669. List<_AnimMoveRestore> to_restore;
  3670. // 1-remove the keys
  3671. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3672. undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
  3673. }
  3674. // 2- remove overlapped keys
  3675. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3676. float newtime = (E->get().pos - from_t) * s + from_t;
  3677. int idx = animation->track_find_key(E->key().track, newtime, true);
  3678. if (idx == -1)
  3679. continue;
  3680. SelectedKey sk;
  3681. sk.key = idx;
  3682. sk.track = E->key().track;
  3683. if (selection.has(sk))
  3684. continue; //already in selection, don't save
  3685. undo_redo->add_do_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newtime);
  3686. _AnimMoveRestore amr;
  3687. amr.key = animation->track_get_key_value(E->key().track, idx);
  3688. amr.track = E->key().track;
  3689. amr.time = newtime;
  3690. amr.transition = animation->track_get_key_transition(E->key().track, idx);
  3691. to_restore.push_back(amr);
  3692. }
  3693. #define _NEW_POS(m_ofs) (((s > 0) ? m_ofs : from_t + (len - (m_ofs - from_t))) - pivot) * ABS(s) + from_t
  3694. // 3-move the keys (re insert them)
  3695. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3696. float newpos = _NEW_POS(E->get().pos);
  3697. undo_redo->add_do_method(animation.ptr(), "track_insert_key", E->key().track, newpos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
  3698. }
  3699. // 4-(undo) remove inserted keys
  3700. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3701. float newpos = _NEW_POS(E->get().pos);
  3702. undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_position", E->key().track, newpos);
  3703. }
  3704. // 5-(undo) reinsert keys
  3705. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3706. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
  3707. }
  3708. // 6-(undo) reinsert overlapped keys
  3709. for (List<_AnimMoveRestore>::Element *E = to_restore.front(); E; E = E->next()) {
  3710. _AnimMoveRestore &amr = E->get();
  3711. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", amr.track, amr.time, amr.key, amr.transition);
  3712. }
  3713. undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
  3714. undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
  3715. // 7-reselect
  3716. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3717. float oldpos = E->get().pos;
  3718. float newpos = _NEW_POS(oldpos);
  3719. if (newpos >= 0)
  3720. undo_redo->add_do_method(this, "_select_at_anim", animation, E->key().track, newpos);
  3721. undo_redo->add_undo_method(this, "_select_at_anim", animation, E->key().track, oldpos);
  3722. }
  3723. #undef _NEW_POS
  3724. undo_redo->commit_action();
  3725. } break;
  3726. case EDIT_DUPLICATE_SELECTION: {
  3727. if (bezier_edit->is_visible()) {
  3728. bezier_edit->duplicate_selection();
  3729. break;
  3730. }
  3731. _anim_duplicate_keys(false);
  3732. } break;
  3733. case EDIT_DUPLICATE_TRANSPOSED: {
  3734. if (bezier_edit->is_visible()) {
  3735. EditorNode::get_singleton()->show_warning(TTR("This option does not work for Bezier editing, as it's only a single track."));
  3736. break;
  3737. }
  3738. _anim_duplicate_keys(true);
  3739. } break;
  3740. case EDIT_DELETE_SELECTION: {
  3741. if (bezier_edit->is_visible()) {
  3742. bezier_edit->delete_selection();
  3743. break;
  3744. }
  3745. if (selection.size()) {
  3746. undo_redo->create_action(TTR("Anim Delete Keys"));
  3747. for (Map<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
  3748. undo_redo->add_do_method(animation.ptr(), "track_remove_key", E->key().track, E->key().key);
  3749. undo_redo->add_undo_method(animation.ptr(), "track_insert_key", E->key().track, E->get().pos, animation->track_get_key_value(E->key().track, E->key().key), animation->track_get_key_transition(E->key().track, E->key().key));
  3750. }
  3751. undo_redo->add_do_method(this, "_clear_selection_for_anim", animation);
  3752. undo_redo->add_undo_method(this, "_clear_selection_for_anim", animation);
  3753. undo_redo->commit_action();
  3754. //selection.clear();
  3755. _update_key_edit();
  3756. }
  3757. } break;
  3758. case EDIT_GOTO_NEXT_STEP: {
  3759. if (animation.is_null())
  3760. break;
  3761. float step = animation->get_step();
  3762. if (step == 0)
  3763. step = 1;
  3764. float pos = timeline->get_play_position();
  3765. pos = Math::stepify(pos + step, step);
  3766. if (pos > animation->get_length())
  3767. pos = animation->get_length();
  3768. set_anim_pos(pos);
  3769. emit_signal("timeline_changed", pos, true);
  3770. } break;
  3771. case EDIT_GOTO_PREV_STEP: {
  3772. if (animation.is_null())
  3773. break;
  3774. float step = animation->get_step();
  3775. if (step == 0)
  3776. step = 1;
  3777. float pos = timeline->get_play_position();
  3778. pos = Math::stepify(pos - step, step);
  3779. if (pos < 0)
  3780. pos = 0;
  3781. set_anim_pos(pos);
  3782. emit_signal("timeline_changed", pos, true);
  3783. } break;
  3784. case EDIT_OPTIMIZE_ANIMATION: {
  3785. optimize_dialog->popup_centered(Size2(250, 180) * EDSCALE);
  3786. } break;
  3787. case EDIT_OPTIMIZE_ANIMATION_CONFIRM: {
  3788. animation->optimize(optimize_linear_error->get_value(), optimize_angular_error->get_value(), optimize_max_angle->get_value());
  3789. _update_tracks();
  3790. undo_redo->clear_history();
  3791. } break;
  3792. case EDIT_CLEAN_UP_ANIMATION: {
  3793. cleanup_dialog->popup_centered_minsize(Size2(300, 0) * EDSCALE);
  3794. } break;
  3795. case EDIT_CLEAN_UP_ANIMATION_CONFIRM: {
  3796. if (cleanup_all->is_pressed()) {
  3797. List<StringName> names;
  3798. AnimationPlayerEditor::singleton->get_player()->get_animation_list(&names);
  3799. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  3800. _cleanup_animation(AnimationPlayerEditor::singleton->get_player()->get_animation(E->get()));
  3801. }
  3802. } else {
  3803. _cleanup_animation(animation);
  3804. }
  3805. } break;
  3806. }
  3807. }
  3808. void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
  3809. for (int i = 0; i < p_animation->get_track_count(); i++) {
  3810. bool prop_exists = false;
  3811. Variant::Type valid_type = Variant::NIL;
  3812. Object *obj = NULL;
  3813. RES res;
  3814. Vector<StringName> leftover_path;
  3815. Node *node = root->get_node_and_resource(p_animation->track_get_path(i), res, leftover_path);
  3816. if (res.is_valid()) {
  3817. obj = res.ptr();
  3818. } else if (node) {
  3819. obj = node;
  3820. }
  3821. if (obj && p_animation->track_get_type(i) == Animation::TYPE_VALUE) {
  3822. valid_type = obj->get_static_property_type_indexed(leftover_path, &prop_exists);
  3823. }
  3824. if (!obj && cleanup_tracks->is_pressed()) {
  3825. p_animation->remove_track(i);
  3826. i--;
  3827. continue;
  3828. }
  3829. if (!prop_exists || p_animation->track_get_type(i) != Animation::TYPE_VALUE || cleanup_keys->is_pressed() == false)
  3830. continue;
  3831. for (int j = 0; j < p_animation->track_get_key_count(i); j++) {
  3832. Variant v = p_animation->track_get_key_value(i, j);
  3833. if (!Variant::can_convert(v.get_type(), valid_type)) {
  3834. p_animation->track_remove_key(i, j);
  3835. j--;
  3836. }
  3837. }
  3838. if (p_animation->track_get_key_count(i) == 0 && cleanup_tracks->is_pressed()) {
  3839. p_animation->remove_track(i);
  3840. i--;
  3841. }
  3842. }
  3843. undo_redo->clear_history();
  3844. _update_tracks();
  3845. }
  3846. void AnimationTrackEditor::_view_group_toggle() {
  3847. _update_tracks();
  3848. view_group->set_icon(get_icon(view_group->is_pressed() ? "AnimationTrackList" : "AnimationTrackGroup", "EditorIcons"));
  3849. }
  3850. void AnimationTrackEditor::_selection_changed() {
  3851. if (selected_filter->is_pressed()) {
  3852. _update_tracks(); //needs updatin
  3853. } else {
  3854. for (int i = 0; i < track_edits.size(); i++) {
  3855. track_edits[i]->update();
  3856. }
  3857. for (int i = 0; i < groups.size(); i++) {
  3858. groups[i]->update();
  3859. }
  3860. }
  3861. }
  3862. float AnimationTrackEditor::snap_time(float p_value) {
  3863. if (snap->is_pressed()) {
  3864. double snap_increment;
  3865. if (timeline->is_using_fps() && step->get_value() > 0)
  3866. snap_increment = 1.0 / step->get_value();
  3867. else
  3868. snap_increment = step->get_value();
  3869. p_value = Math::stepify(p_value, snap_increment);
  3870. }
  3871. return p_value;
  3872. }
  3873. void AnimationTrackEditor::_show_imported_anim_warning() const {
  3874. EditorNode::get_singleton()->show_warning(TTR("This animation belongs to an imported scene, so changes to imported tracks will not be saved.\n\n"
  3875. "To enable the ability to add custom tracks, navigate to the scene's import settings and set\n"
  3876. "\"Animation > Storage\" to \"Files\", enable \"Animation > Keep Custom Tracks\", then re-import.\n"
  3877. "Alternatively, use an import preset that imports animations to separate files."),
  3878. TTR("Warning: Editing imported animation"));
  3879. }
  3880. void AnimationTrackEditor::_bind_methods() {
  3881. ClassDB::bind_method("_animation_changed", &AnimationTrackEditor::_animation_changed);
  3882. ClassDB::bind_method("_animation_update", &AnimationTrackEditor::_animation_update);
  3883. ClassDB::bind_method("_timeline_changed", &AnimationTrackEditor::_timeline_changed);
  3884. ClassDB::bind_method("_track_remove_request", &AnimationTrackEditor::_track_remove_request);
  3885. ClassDB::bind_method("_name_limit_changed", &AnimationTrackEditor::_name_limit_changed);
  3886. ClassDB::bind_method("_update_scroll", &AnimationTrackEditor::_update_scroll);
  3887. ClassDB::bind_method("_update_tracks", &AnimationTrackEditor::_update_tracks);
  3888. ClassDB::bind_method("_update_step", &AnimationTrackEditor::_update_step);
  3889. ClassDB::bind_method("_update_length", &AnimationTrackEditor::_update_length);
  3890. ClassDB::bind_method("_dropped_track", &AnimationTrackEditor::_dropped_track);
  3891. ClassDB::bind_method("_add_track", &AnimationTrackEditor::_add_track);
  3892. ClassDB::bind_method("_new_track_node_selected", &AnimationTrackEditor::_new_track_node_selected);
  3893. ClassDB::bind_method("_new_track_property_selected", &AnimationTrackEditor::_new_track_property_selected);
  3894. ClassDB::bind_method("_root_removed", &AnimationTrackEditor::_root_removed);
  3895. ClassDB::bind_method("_confirm_insert_list", &AnimationTrackEditor::_confirm_insert_list);
  3896. ClassDB::bind_method("_insert_delay", &AnimationTrackEditor::_insert_delay);
  3897. ClassDB::bind_method("_timeline_value_changed", &AnimationTrackEditor::_timeline_value_changed);
  3898. ClassDB::bind_method("_insert_key_from_track", &AnimationTrackEditor::_insert_key_from_track);
  3899. ClassDB::bind_method("_add_method_key", &AnimationTrackEditor::_add_method_key);
  3900. ClassDB::bind_method("_key_selected", &AnimationTrackEditor::_key_selected);
  3901. ClassDB::bind_method("_key_deselected", &AnimationTrackEditor::_key_deselected);
  3902. ClassDB::bind_method("_clear_selection", &AnimationTrackEditor::_clear_selection);
  3903. ClassDB::bind_method("_move_selection_begin", &AnimationTrackEditor::_move_selection_begin);
  3904. ClassDB::bind_method("_move_selection", &AnimationTrackEditor::_move_selection);
  3905. ClassDB::bind_method("_move_selection_commit", &AnimationTrackEditor::_move_selection_commit);
  3906. ClassDB::bind_method("_move_selection_cancel", &AnimationTrackEditor::_move_selection_cancel);
  3907. ClassDB::bind_method("_clear_selection_for_anim", &AnimationTrackEditor::_clear_selection_for_anim);
  3908. ClassDB::bind_method("_select_at_anim", &AnimationTrackEditor::_select_at_anim);
  3909. ClassDB::bind_method("_scroll_input", &AnimationTrackEditor::_scroll_input);
  3910. ClassDB::bind_method("_box_selection_draw", &AnimationTrackEditor::_box_selection_draw);
  3911. ClassDB::bind_method("_bezier_edit", &AnimationTrackEditor::_bezier_edit);
  3912. ClassDB::bind_method("_cancel_bezier_edit", &AnimationTrackEditor::_cancel_bezier_edit);
  3913. ClassDB::bind_method("_edit_menu_pressed", &AnimationTrackEditor::_edit_menu_pressed);
  3914. ClassDB::bind_method("_view_group_toggle", &AnimationTrackEditor::_view_group_toggle);
  3915. ClassDB::bind_method("_selection_changed", &AnimationTrackEditor::_selection_changed);
  3916. ClassDB::bind_method("_snap_mode_changed", &AnimationTrackEditor::_snap_mode_changed);
  3917. ClassDB::bind_method("_show_imported_anim_warning", &AnimationTrackEditor::_show_imported_anim_warning);
  3918. ADD_SIGNAL(MethodInfo("timeline_changed", PropertyInfo(Variant::REAL, "position"), PropertyInfo(Variant::BOOL, "drag")));
  3919. ADD_SIGNAL(MethodInfo("keying_changed"));
  3920. ADD_SIGNAL(MethodInfo("animation_len_changed", PropertyInfo(Variant::REAL, "len")));
  3921. ADD_SIGNAL(MethodInfo("animation_step_changed", PropertyInfo(Variant::REAL, "step")));
  3922. }
  3923. AnimationTrackEditor::AnimationTrackEditor() {
  3924. root = NULL;
  3925. undo_redo = EditorNode::get_singleton()->get_undo_redo();
  3926. main_panel = memnew(PanelContainer);
  3927. add_child(main_panel);
  3928. main_panel->set_v_size_flags(SIZE_EXPAND_FILL);
  3929. HBoxContainer *timeline_scroll = memnew(HBoxContainer);
  3930. main_panel->add_child(timeline_scroll);
  3931. timeline_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
  3932. VBoxContainer *timeline_vbox = memnew(VBoxContainer);
  3933. timeline_scroll->add_child(timeline_vbox);
  3934. timeline_vbox->set_v_size_flags(SIZE_EXPAND_FILL);
  3935. timeline_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
  3936. timeline_vbox->add_constant_override("separation", 0);
  3937. timeline = memnew(AnimationTimelineEdit);
  3938. timeline->set_undo_redo(undo_redo);
  3939. timeline_vbox->add_child(timeline);
  3940. timeline->connect("timeline_changed", this, "_timeline_changed");
  3941. timeline->connect("name_limit_changed", this, "_name_limit_changed");
  3942. timeline->connect("track_added", this, "_add_track");
  3943. timeline->connect("value_changed", this, "_timeline_value_changed");
  3944. timeline->connect("length_changed", this, "_update_length");
  3945. scroll = memnew(ScrollContainer);
  3946. timeline_vbox->add_child(scroll);
  3947. scroll->set_v_size_flags(SIZE_EXPAND_FILL);
  3948. VScrollBar *sb = scroll->get_v_scrollbar();
  3949. scroll->remove_child(sb);
  3950. timeline_scroll->add_child(sb); //move here so timeline and tracks are always aligned
  3951. scroll->connect("gui_input", this, "_scroll_input");
  3952. bezier_edit = memnew(AnimationBezierTrackEdit);
  3953. timeline_vbox->add_child(bezier_edit);
  3954. bezier_edit->set_undo_redo(undo_redo);
  3955. bezier_edit->set_editor(this);
  3956. bezier_edit->set_timeline(timeline);
  3957. bezier_edit->hide();
  3958. bezier_edit->set_v_size_flags(SIZE_EXPAND_FILL);
  3959. bezier_edit->connect("close_request", this, "_cancel_bezier_edit");
  3960. timeline_vbox->set_custom_minimum_size(Size2(0, 150) * EDSCALE);
  3961. hscroll = memnew(HScrollBar);
  3962. hscroll->share(timeline);
  3963. hscroll->hide();
  3964. hscroll->connect("value_changed", this, "_update_scroll");
  3965. timeline_vbox->add_child(hscroll);
  3966. timeline->set_hscroll(hscroll);
  3967. track_vbox = memnew(VBoxContainer);
  3968. scroll->add_child(track_vbox);
  3969. track_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
  3970. scroll->set_enable_h_scroll(false);
  3971. scroll->set_enable_v_scroll(true);
  3972. track_vbox->add_constant_override("separation", 0);
  3973. //timeline_vbox->add_child(memnew(HSeparator));
  3974. HBoxContainer *bottom_hb = memnew(HBoxContainer);
  3975. add_child(bottom_hb);
  3976. imported_anim_warning = memnew(Button);
  3977. imported_anim_warning->hide();
  3978. imported_anim_warning->set_tooltip(TTR("Warning: Editing imported animation"));
  3979. imported_anim_warning->connect("pressed", this, "_show_imported_anim_warning");
  3980. bottom_hb->add_child(imported_anim_warning);
  3981. bottom_hb->add_spacer();
  3982. selected_filter = memnew(ToolButton);
  3983. selected_filter->connect("pressed", this, "_view_group_toggle"); //same function works the same
  3984. selected_filter->set_toggle_mode(true);
  3985. selected_filter->set_tooltip(TTR("Only show tracks from nodes selected in tree."));
  3986. bottom_hb->add_child(selected_filter);
  3987. view_group = memnew(ToolButton);
  3988. view_group->connect("pressed", this, "_view_group_toggle");
  3989. view_group->set_toggle_mode(true);
  3990. view_group->set_tooltip(TTR("Group tracks by node or display them as plain list."));
  3991. bottom_hb->add_child(view_group);
  3992. bottom_hb->add_child(memnew(VSeparator));
  3993. snap = memnew(ToolButton);
  3994. snap->set_text(TTR("Snap:") + " ");
  3995. bottom_hb->add_child(snap);
  3996. snap->set_disabled(true);
  3997. snap->set_toggle_mode(true);
  3998. snap->set_pressed(true);
  3999. step = memnew(EditorSpinSlider);
  4000. step->set_min(0);
  4001. step->set_max(1000000);
  4002. step->set_step(0.01);
  4003. step->set_hide_slider(true);
  4004. step->set_custom_minimum_size(Size2(100, 0) * EDSCALE);
  4005. step->set_tooltip(TTR("Animation step value."));
  4006. bottom_hb->add_child(step);
  4007. step->connect("value_changed", this, "_update_step");
  4008. step->set_read_only(true);
  4009. snap_mode = memnew(OptionButton);
  4010. snap_mode->add_item(TTR("Seconds"));
  4011. snap_mode->add_item(TTR("FPS"));
  4012. bottom_hb->add_child(snap_mode);
  4013. snap_mode->connect("item_selected", this, "_snap_mode_changed");
  4014. snap_mode->set_disabled(true);
  4015. bottom_hb->add_child(memnew(VSeparator));
  4016. zoom_icon = memnew(TextureRect);
  4017. zoom_icon->set_v_size_flags(SIZE_SHRINK_CENTER);
  4018. bottom_hb->add_child(zoom_icon);
  4019. zoom = memnew(HSlider);
  4020. zoom->set_step(0.01);
  4021. zoom->set_min(0.0);
  4022. zoom->set_max(2.0);
  4023. zoom->set_value(1.0);
  4024. zoom->set_custom_minimum_size(Size2(200, 0) * EDSCALE);
  4025. zoom->set_v_size_flags(SIZE_SHRINK_CENTER);
  4026. bottom_hb->add_child(zoom);
  4027. timeline->set_zoom(zoom);
  4028. edit = memnew(MenuButton);
  4029. edit->set_text(TTR("Edit"));
  4030. edit->set_flat(false);
  4031. edit->set_disabled(true);
  4032. edit->set_tooltip(TTR("Animation properties."));
  4033. edit->get_popup()->add_item(TTR("Copy Tracks"), EDIT_COPY_TRACKS);
  4034. edit->get_popup()->add_item(TTR("Paste Tracks"), EDIT_PASTE_TRACKS);
  4035. edit->get_popup()->add_separator();
  4036. edit->get_popup()->add_item(TTR("Scale Selection"), EDIT_SCALE_SELECTION);
  4037. edit->get_popup()->add_item(TTR("Scale From Cursor"), EDIT_SCALE_FROM_CURSOR);
  4038. edit->get_popup()->add_separator();
  4039. edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection", TTR("Duplicate Selection"), KEY_MASK_CMD | KEY_D), EDIT_DUPLICATE_SELECTION);
  4040. edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/duplicate_selection_transposed", TTR("Duplicate Transposed"), KEY_MASK_SHIFT | KEY_MASK_CMD | KEY_D), EDIT_DUPLICATE_TRANSPOSED);
  4041. edit->get_popup()->set_item_shortcut_disabled(edit->get_popup()->get_item_index(EDIT_DUPLICATE_SELECTION), true);
  4042. edit->get_popup()->set_item_shortcut_disabled(edit->get_popup()->get_item_index(EDIT_DUPLICATE_TRANSPOSED), true);
  4043. edit->get_popup()->add_separator();
  4044. edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/delete_selection", TTR("Delete Selection"), KEY_DELETE), EDIT_DELETE_SELECTION);
  4045. edit->get_popup()->set_item_shortcut_disabled(edit->get_popup()->get_item_index(EDIT_DELETE_SELECTION), true);
  4046. //this shortcut will be checked from the track itself. so no need to enable it here (will conflict with scenetree dock)
  4047. edit->get_popup()->add_separator();
  4048. edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_next_step", TTR("Go to Next Step"), KEY_MASK_CMD | KEY_RIGHT), EDIT_GOTO_NEXT_STEP);
  4049. edit->get_popup()->add_shortcut(ED_SHORTCUT("animation_editor/goto_prev_step", TTR("Go to Previous Step"), KEY_MASK_CMD | KEY_LEFT), EDIT_GOTO_PREV_STEP);
  4050. edit->get_popup()->add_separator();
  4051. edit->get_popup()->add_item(TTR("Optimize Animation"), EDIT_OPTIMIZE_ANIMATION);
  4052. edit->get_popup()->add_item(TTR("Clean-Up Animation"), EDIT_CLEAN_UP_ANIMATION);
  4053. edit->get_popup()->connect("id_pressed", this, "_edit_menu_pressed");
  4054. pick_track = memnew(SceneTreeDialog);
  4055. add_child(pick_track);
  4056. pick_track->set_title(TTR("Pick the node that will be animated:"));
  4057. pick_track->connect("selected", this, "_new_track_node_selected");
  4058. prop_selector = memnew(PropertySelector);
  4059. add_child(prop_selector);
  4060. prop_selector->connect("selected", this, "_new_track_property_selected");
  4061. method_selector = memnew(PropertySelector);
  4062. add_child(method_selector);
  4063. method_selector->connect("selected", this, "_add_method_key");
  4064. inserting = false;
  4065. insert_query = false;
  4066. insert_frame = 0;
  4067. insert_queue = false;
  4068. insert_confirm = memnew(ConfirmationDialog);
  4069. add_child(insert_confirm);
  4070. insert_confirm->connect("confirmed", this, "_confirm_insert_list");
  4071. VBoxContainer *icvb = memnew(VBoxContainer);
  4072. insert_confirm->add_child(icvb);
  4073. insert_confirm_text = memnew(Label);
  4074. icvb->add_child(insert_confirm_text);
  4075. insert_confirm_bezier = memnew(CheckBox);
  4076. insert_confirm_bezier->set_text(TTR("Use Bezier Curves"));
  4077. icvb->add_child(insert_confirm_bezier);
  4078. keying = false;
  4079. moving_selection = 0;
  4080. key_edit = NULL;
  4081. box_selection = memnew(Control);
  4082. add_child(box_selection);
  4083. box_selection->set_as_toplevel(true);
  4084. box_selection->set_mouse_filter(MOUSE_FILTER_IGNORE);
  4085. box_selection->hide();
  4086. box_selection->connect("draw", this, "_box_selection_draw");
  4087. box_selecting = false;
  4088. //default plugins
  4089. Ref<AnimationTrackEditDefaultPlugin> def_plugin;
  4090. def_plugin.instance();
  4091. add_track_edit_plugin(def_plugin);
  4092. //dialogs
  4093. optimize_dialog = memnew(ConfirmationDialog);
  4094. add_child(optimize_dialog);
  4095. optimize_dialog->set_title(TTR("Anim. Optimizer"));
  4096. VBoxContainer *optimize_vb = memnew(VBoxContainer);
  4097. optimize_dialog->add_child(optimize_vb);
  4098. optimize_linear_error = memnew(SpinBox);
  4099. optimize_linear_error->set_max(1.0);
  4100. optimize_linear_error->set_min(0.001);
  4101. optimize_linear_error->set_step(0.001);
  4102. optimize_linear_error->set_value(0.05);
  4103. optimize_vb->add_margin_child(TTR("Max. Linear Error:"), optimize_linear_error);
  4104. optimize_angular_error = memnew(SpinBox);
  4105. optimize_angular_error->set_max(1.0);
  4106. optimize_angular_error->set_min(0.001);
  4107. optimize_angular_error->set_step(0.001);
  4108. optimize_angular_error->set_value(0.01);
  4109. optimize_vb->add_margin_child(TTR("Max. Angular Error:"), optimize_angular_error);
  4110. optimize_max_angle = memnew(SpinBox);
  4111. optimize_vb->add_margin_child(TTR("Max Optimizable Angle:"), optimize_max_angle);
  4112. optimize_max_angle->set_max(360.0);
  4113. optimize_max_angle->set_min(0.0);
  4114. optimize_max_angle->set_step(0.1);
  4115. optimize_max_angle->set_value(22);
  4116. optimize_dialog->get_ok()->set_text(TTR("Optimize"));
  4117. optimize_dialog->connect("confirmed", this, "_edit_menu_pressed", varray(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
  4118. //
  4119. cleanup_dialog = memnew(ConfirmationDialog);
  4120. add_child(cleanup_dialog);
  4121. VBoxContainer *cleanup_vb = memnew(VBoxContainer);
  4122. cleanup_dialog->add_child(cleanup_vb);
  4123. cleanup_keys = memnew(CheckButton);
  4124. cleanup_keys->set_text(TTR("Remove invalid keys"));
  4125. cleanup_keys->set_pressed(true);
  4126. cleanup_vb->add_child(cleanup_keys);
  4127. cleanup_tracks = memnew(CheckButton);
  4128. cleanup_tracks->set_text(TTR("Remove unresolved and empty tracks"));
  4129. cleanup_tracks->set_pressed(true);
  4130. cleanup_vb->add_child(cleanup_tracks);
  4131. cleanup_all = memnew(CheckButton);
  4132. cleanup_all->set_text(TTR("Clean-up all animations"));
  4133. cleanup_vb->add_child(cleanup_all);
  4134. cleanup_dialog->set_title(TTR("Clean-Up Animation(s) (NO UNDO!)"));
  4135. cleanup_dialog->get_ok()->set_text(TTR("Clean-Up"));
  4136. cleanup_dialog->connect("confirmed", this, "_edit_menu_pressed", varray(EDIT_CLEAN_UP_ANIMATION_CONFIRM));
  4137. //
  4138. scale_dialog = memnew(ConfirmationDialog);
  4139. VBoxContainer *vbc = memnew(VBoxContainer);
  4140. scale_dialog->add_child(vbc);
  4141. scale = memnew(SpinBox);
  4142. scale->set_min(-99999);
  4143. scale->set_max(99999);
  4144. scale->set_step(0.001);
  4145. vbc->add_margin_child(TTR("Scale Ratio:"), scale);
  4146. scale_dialog->connect("confirmed", this, "_edit_menu_pressed", varray(EDIT_SCALE_CONFIRM));
  4147. add_child(scale_dialog);
  4148. track_copy_dialog = memnew(ConfirmationDialog);
  4149. add_child(track_copy_dialog);
  4150. track_copy_dialog->set_title(TTR("Select tracks to copy:"));
  4151. track_copy_dialog->get_ok()->set_text(TTR("Copy"));
  4152. track_copy_select = memnew(Tree);
  4153. track_copy_select->set_hide_root(true);
  4154. track_copy_dialog->add_child(track_copy_select);
  4155. track_copy_dialog->connect("confirmed", this, "_edit_menu_pressed", varray(EDIT_COPY_TRACKS_CONFIRM));
  4156. animation_changing_awaiting_update = false;
  4157. }
  4158. AnimationTrackEditor::~AnimationTrackEditor() {
  4159. if (key_edit) {
  4160. memdelete(key_edit);
  4161. }
  4162. }