| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569 | /*************************************************************************//*  visual_script_editor.cpp                                             *//*************************************************************************//*                       This file is part of:                           *//*                           GODOT ENGINE                                *//*                      https://godotengine.org                          *//*************************************************************************//* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.                 *//* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).   *//*                                                                       *//* Permission is hereby granted, free of charge, to any person obtaining *//* a copy of this software and associated documentation files (the       *//* "Software"), to deal in the Software without restriction, including   *//* without limitation the rights to use, copy, modify, merge, publish,   *//* distribute, sublicense, and/or sell copies of the Software, and to    *//* permit persons to whom the Software is furnished to do so, subject to *//* the following conditions:                                             *//*                                                                       *//* The above copyright notice and this permission notice shall be        *//* included in all copies or substantial portions of the Software.       *//*                                                                       *//* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *//* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *//* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*//* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY  *//* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,  *//* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     *//* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                *//*************************************************************************/#include "visual_script_editor.h"#include "core/input/input.h"#include "core/object/class_db.h"#include "core/object/script_language.h"#include "core/os/keyboard.h"#include "core/variant/variant.h"#include "editor/editor_node.h"#include "editor/editor_resource_preview.h"#include "editor/editor_scale.h"#include "scene/main/window.h"#include "visual_script_expression.h"#include "visual_script_flow_control.h"#include "visual_script_func_nodes.h"#include "visual_script_nodes.h"#ifdef TOOLS_ENABLEDclass VisualScriptEditorSignalEdit : public Object {	GDCLASS(VisualScriptEditorSignalEdit, Object);	StringName sig;public:	UndoRedo *undo_redo;	Ref<VisualScript> script;protected:	static void _bind_methods() {		ClassDB::bind_method("_sig_changed", &VisualScriptEditorSignalEdit::_sig_changed);		ADD_SIGNAL(MethodInfo("changed"));	}	void _sig_changed() {		notify_property_list_changed();		emit_signal(SNAME("changed"));	}	bool _set(const StringName &p_name, const Variant &p_value) {		if (sig == StringName()) {			return false;		}		if (p_name == "argument_count") {			int new_argc = p_value;			int argc = script->custom_signal_get_argument_count(sig);			if (argc == new_argc) {				return true;			}			undo_redo->create_action(TTR("Change Signal Arguments"));			if (new_argc < argc) {				for (int i = new_argc; i < argc; i++) {					undo_redo->add_do_method(script.ptr(), "custom_signal_remove_argument", sig, new_argc);					undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", sig, script->custom_signal_get_argument_name(sig, i), script->custom_signal_get_argument_type(sig, i), -1);				}			} else if (new_argc > argc) {				for (int i = argc; i < new_argc; i++) {					undo_redo->add_do_method(script.ptr(), "custom_signal_add_argument", sig, Variant::NIL, "arg" + itos(i + 1), -1);					undo_redo->add_undo_method(script.ptr(), "custom_signal_remove_argument", sig, argc);				}			}			undo_redo->add_do_method(this, "_sig_changed");			undo_redo->add_undo_method(this, "_sig_changed");			undo_redo->commit_action();			return true;		}		if (String(p_name).begins_with("argument/")) {			int idx = String(p_name).get_slice("/", 1).to_int() - 1;			ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false);			String what = String(p_name).get_slice("/", 2);			if (what == "type") {				int old_type = script->custom_signal_get_argument_type(sig, idx);				int new_type = p_value;				undo_redo->create_action(TTR("Change Argument Type"));				undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, new_type);				undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_type", sig, idx, old_type);				undo_redo->commit_action();				return true;			}			if (what == "name") {				String old_name = script->custom_signal_get_argument_name(sig, idx);				String new_name = p_value;				undo_redo->create_action(TTR("Change Argument name"));				undo_redo->add_do_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, new_name);				undo_redo->add_undo_method(script.ptr(), "custom_signal_set_argument_name", sig, idx, old_name);				undo_redo->commit_action();				return true;			}		}		return false;	}	bool _get(const StringName &p_name, Variant &r_ret) const {		if (sig == StringName()) {			return false;		}		if (p_name == "argument_count") {			r_ret = script->custom_signal_get_argument_count(sig);			return true;		}		if (String(p_name).begins_with("argument/")) {			int idx = String(p_name).get_slice("/", 1).to_int() - 1;			ERR_FAIL_INDEX_V(idx, script->custom_signal_get_argument_count(sig), false);			String what = String(p_name).get_slice("/", 2);			if (what == "type") {				r_ret = script->custom_signal_get_argument_type(sig, idx);				return true;			}			if (what == "name") {				r_ret = script->custom_signal_get_argument_name(sig, idx);				return true;			}		}		return false;	}	void _get_property_list(List<PropertyInfo> *p_list) const {		if (sig == StringName()) {			return;		}		p_list->push_back(PropertyInfo(Variant::INT, "argument_count", PROPERTY_HINT_RANGE, "0,256"));		String argt = "Variant";		for (int i = 1; i < Variant::VARIANT_MAX; i++) {			argt += "," + Variant::get_type_name(Variant::Type(i));		}		for (int i = 0; i < script->custom_signal_get_argument_count(sig); i++) {			p_list->push_back(PropertyInfo(Variant::INT, "argument/" + itos(i + 1) + "/type", PROPERTY_HINT_ENUM, argt));			p_list->push_back(PropertyInfo(Variant::STRING, "argument/" + itos(i + 1) + "/name"));		}	}public:	void edit(const StringName &p_sig) {		sig = p_sig;		notify_property_list_changed();	}	VisualScriptEditorSignalEdit() { undo_redo = nullptr; }};class VisualScriptEditorVariableEdit : public Object {	GDCLASS(VisualScriptEditorVariableEdit, Object);	StringName var;public:	UndoRedo *undo_redo;	Ref<VisualScript> script;protected:	static void _bind_methods() {		ClassDB::bind_method("_var_changed", &VisualScriptEditorVariableEdit::_var_changed);		ClassDB::bind_method("_var_value_changed", &VisualScriptEditorVariableEdit::_var_value_changed);		ADD_SIGNAL(MethodInfo("changed"));	}	void _var_changed() {		notify_property_list_changed();		emit_signal(SNAME("changed"));	}	void _var_value_changed() {		emit_signal(SNAME("changed"));	}	bool _set(const StringName &p_name, const Variant &p_value) {		if (var == StringName()) {			return false;		}		if (String(p_name) == "value") {			undo_redo->create_action(TTR("Set Variable Default Value"));			Variant current = script->get_variable_default_value(var);			undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, p_value);			undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, current);			undo_redo->add_do_method(this, "_var_value_changed");			undo_redo->add_undo_method(this, "_var_value_changed");			undo_redo->commit_action();			return true;		}		Dictionary d = script->call("get_variable_info", var);		if (String(p_name) == "type") {			Dictionary dc = d.duplicate();			dc["type"] = p_value;			undo_redo->create_action(TTR("Set Variable Type"));			undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);			undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);			// Setting the default value.			Variant::Type type = (Variant::Type)(int)p_value;			if (type != Variant::NIL) {				Variant default_value;				Callable::CallError ce;				Variant::construct(type, default_value, nullptr, 0, ce);				if (ce.error == Callable::CallError::CALL_OK) {					undo_redo->add_do_method(script.ptr(), "set_variable_default_value", var, default_value);					undo_redo->add_undo_method(script.ptr(), "set_variable_default_value", var, dc["value"]);				}			}			undo_redo->add_do_method(this, "_var_changed");			undo_redo->add_undo_method(this, "_var_changed");			undo_redo->commit_action();			return true;		}		if (String(p_name) == "hint") {			Dictionary dc = d.duplicate();			dc["hint"] = p_value;			undo_redo->create_action(TTR("Set Variable Type"));			undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);			undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);			undo_redo->add_do_method(this, "_var_changed");			undo_redo->add_undo_method(this, "_var_changed");			undo_redo->commit_action();			return true;		}		if (String(p_name) == "hint_string") {			Dictionary dc = d.duplicate();			dc["hint_string"] = p_value;			undo_redo->create_action(TTR("Set Variable Type"));			undo_redo->add_do_method(script.ptr(), "set_variable_info", var, dc);			undo_redo->add_undo_method(script.ptr(), "set_variable_info", var, d);			undo_redo->add_do_method(this, "_var_changed");			undo_redo->add_undo_method(this, "_var_changed");			undo_redo->commit_action();			return true;		}		if (String(p_name) == "export") {			script->set_variable_export(var, p_value);			EditorNode::get_singleton()->get_inspector()->update_tree();			return true;		}		return false;	}	bool _get(const StringName &p_name, Variant &r_ret) const {		if (var == StringName()) {			return false;		}		if (String(p_name) == "value") {			r_ret = script->get_variable_default_value(var);			return true;		}		PropertyInfo pinfo = script->get_variable_info(var);		if (String(p_name) == "type") {			r_ret = pinfo.type;			return true;		}		if (String(p_name) == "hint") {			r_ret = pinfo.hint;			return true;		}		if (String(p_name) == "hint_string") {			r_ret = pinfo.hint_string;			return true;		}		if (String(p_name) == "export") {			r_ret = script->get_variable_export(var);			return true;		}		return false;	}	void _get_property_list(List<PropertyInfo> *p_list) const {		if (var == StringName()) {			return;		}		String argt = "Variant";		for (int i = 1; i < Variant::VARIANT_MAX; i++) {			argt += "," + Variant::get_type_name(Variant::Type(i));		}		p_list->push_back(PropertyInfo(Variant::INT, "type", PROPERTY_HINT_ENUM, argt));		p_list->push_back(PropertyInfo(script->get_variable_info(var).type, "value", script->get_variable_info(var).hint, script->get_variable_info(var).hint_string, PROPERTY_USAGE_DEFAULT));		// Update this when PropertyHint changes.		p_list->push_back(PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_ENUM, "None,Range,ExpRange,Enum,ExpEasing,Length,SpriteFrame,KeyAccel,Flags,Layers2dRender,Layers2dPhysics,Layer3dRender,Layer3dPhysics,File,Dir,GlobalFile,GlobalDir,ResourceType,MultilineText,PlaceholderText,ColorNoAlpha,ImageCompressLossy,ImageCompressLossLess,ObjectId,String,NodePathToEditedNode,MethodOfVariantType,MethodOfBaseType,MethodOfInstance,MethodOfScript,PropertyOfVariantType,PropertyOfBaseType,PropertyOfInstance,PropertyOfScript,ObjectTooBig,NodePathValidTypes"));		p_list->push_back(PropertyInfo(Variant::STRING, "hint_string"));		p_list->push_back(PropertyInfo(Variant::BOOL, "export"));	}public:	void edit(const StringName &p_var) {		var = p_var;		notify_property_list_changed();	}	VisualScriptEditorVariableEdit() { undo_redo = nullptr; }};static Color _color_from_type(Variant::Type p_type, bool dark_theme = true) {	Color color;	if (dark_theme) {		switch (p_type) {			case Variant::NIL:				color = Color(0.41, 0.93, 0.74);				break;			case Variant::BOOL:				color = Color(0.55, 0.65, 0.94);				break;			case Variant::INT:				color = Color(0.49, 0.78, 0.94);				break;			case Variant::FLOAT:				color = Color(0.38, 0.85, 0.96);				break;			case Variant::STRING:				color = Color(0.42, 0.65, 0.93);				break;			case Variant::VECTOR2:				color = Color(0.74, 0.57, 0.95);				break;			case Variant::VECTOR2I:				color = Color(0.74, 0.57, 0.95);				break;			case Variant::RECT2:				color = Color(0.95, 0.57, 0.65);				break;			case Variant::RECT2I:				color = Color(0.95, 0.57, 0.65);				break;			case Variant::VECTOR3:				color = Color(0.84, 0.49, 0.93);				break;			case Variant::VECTOR3I:				color = Color(0.84, 0.49, 0.93);				break;			case Variant::TRANSFORM2D:				color = Color(0.77, 0.93, 0.41);				break;			case Variant::PLANE:				color = Color(0.97, 0.44, 0.44);				break;			case Variant::QUATERNION:				color = Color(0.93, 0.41, 0.64);				break;			case Variant::AABB:				color = Color(0.93, 0.47, 0.57);				break;			case Variant::BASIS:				color = Color(0.89, 0.93, 0.41);				break;			case Variant::TRANSFORM3D:				color = Color(0.96, 0.66, 0.43);				break;			case Variant::COLOR:				color = Color(0.62, 1.0, 0.44);				break;			case Variant::NODE_PATH:				color = Color(0.41, 0.58, 0.93);				break;			case Variant::RID:				color = Color(0.41, 0.93, 0.6);				break;			case Variant::OBJECT:				color = Color(0.47, 0.95, 0.91);				break;			case Variant::DICTIONARY:				color = Color(0.47, 0.93, 0.69);				break;			case Variant::ARRAY:				color = Color(0.88, 0.88, 0.88);				break;			case Variant::PACKED_BYTE_ARRAY:				color = Color(0.67, 0.96, 0.78);				break;			case Variant::PACKED_INT32_ARRAY:				color = Color(0.69, 0.86, 0.96);				break;			case Variant::PACKED_FLOAT32_ARRAY:				color = Color(0.59, 0.91, 0.97);				break;			case Variant::PACKED_INT64_ARRAY:				color = Color(0.69, 0.86, 0.96);				break;			case Variant::PACKED_FLOAT64_ARRAY:				color = Color(0.59, 0.91, 0.97);				break;			case Variant::PACKED_STRING_ARRAY:				color = Color(0.62, 0.77, 0.95);				break;			case Variant::PACKED_VECTOR2_ARRAY:				color = Color(0.82, 0.7, 0.96);				break;			case Variant::PACKED_VECTOR3_ARRAY:				color = Color(0.87, 0.61, 0.95);				break;			case Variant::PACKED_COLOR_ARRAY:				color = Color(0.91, 1.0, 0.59);				break;			default:				color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.7, 0.7);		}	} else {		switch (p_type) {			case Variant::NIL:				color = Color(0.15, 0.89, 0.63);				break;			case Variant::BOOL:				color = Color(0.43, 0.56, 0.92);				break;			case Variant::INT:				color = Color(0.31, 0.7, 0.91);				break;			case Variant::FLOAT:				color = Color(0.15, 0.8, 0.94);				break;			case Variant::STRING:				color = Color(0.27, 0.56, 0.91);				break;			case Variant::VECTOR2:				color = Color(0.68, 0.46, 0.93);				break;			case Variant::VECTOR2I:				color = Color(0.68, 0.46, 0.93);				break;			case Variant::RECT2:				color = Color(0.93, 0.46, 0.56);				break;			case Variant::RECT2I:				color = Color(0.93, 0.46, 0.56);				break;			case Variant::VECTOR3:				color = Color(0.86, 0.42, 0.93);				break;			case Variant::VECTOR3I:				color = Color(0.86, 0.42, 0.93);				break;			case Variant::TRANSFORM2D:				color = Color(0.59, 0.81, 0.1);				break;			case Variant::PLANE:				color = Color(0.97, 0.44, 0.44);				break;			case Variant::QUATERNION:				color = Color(0.93, 0.41, 0.64);				break;			case Variant::AABB:				color = Color(0.93, 0.47, 0.57);				break;			case Variant::BASIS:				color = Color(0.7, 0.73, 0.1);				break;			case Variant::TRANSFORM3D:				color = Color(0.96, 0.56, 0.28);				break;			case Variant::COLOR:				color = Color(0.24, 0.75, 0.0);				break;			case Variant::NODE_PATH:				color = Color(0.41, 0.58, 0.93);				break;			case Variant::RID:				color = Color(0.17, 0.9, 0.45);				break;			case Variant::OBJECT:				color = Color(0.07, 0.84, 0.76);				break;			case Variant::DICTIONARY:				color = Color(0.34, 0.91, 0.62);				break;			case Variant::ARRAY:				color = Color(0.45, 0.45, 0.45);				break;			case Variant::PACKED_BYTE_ARRAY:				color = Color(0.38, 0.92, 0.6);				break;			case Variant::PACKED_INT32_ARRAY:				color = Color(0.38, 0.73, 0.92);				break;			case Variant::PACKED_FLOAT32_ARRAY:				color = Color(0.25, 0.83, 0.95);				break;			case Variant::PACKED_INT64_ARRAY:				color = Color(0.38, 0.73, 0.92);				break;			case Variant::PACKED_FLOAT64_ARRAY:				color = Color(0.25, 0.83, 0.95);				break;			case Variant::PACKED_STRING_ARRAY:				color = Color(0.38, 0.62, 0.92);				break;			case Variant::PACKED_VECTOR2_ARRAY:				color = Color(0.62, 0.36, 0.92);				break;			case Variant::PACKED_VECTOR3_ARRAY:				color = Color(0.79, 0.35, 0.92);				break;			case Variant::PACKED_COLOR_ARRAY:				color = Color(0.57, 0.73, 0.0);				break;			default:				color.set_hsv(p_type / float(Variant::VARIANT_MAX), 0.3, 0.3);		}	}	return color;}void VisualScriptEditor::_update_graph_connections() {	graph->clear_connections();	List<VisualScript::SequenceConnection> sequence_conns;	script->get_sequence_connection_list(&sequence_conns);	for (const VisualScript::SequenceConnection &E : sequence_conns) {		graph->connect_node(itos(E.from_node), E.from_output, itos(E.to_node), 0);	}	List<VisualScript::DataConnection> data_conns;	script->get_data_connection_list(&data_conns);	for (VisualScript::DataConnection &dc : data_conns) {		Ref<VisualScriptNode> from_node = script->get_node(dc.from_node);		Ref<VisualScriptNode> to_node = script->get_node(dc.to_node);		if (to_node->has_input_sequence_port()) {			dc.to_port++;		}		dc.from_port += from_node->get_output_sequence_port_count();		graph->connect_node(itos(dc.from_node), dc.from_port, itos(dc.to_node), dc.to_port);	}}void VisualScriptEditor::_update_graph(int p_only_id) {	if (updating_graph) {		return;	}	updating_graph = true;	//byebye all nodes	if (p_only_id >= 0) {		if (graph->has_node(itos(p_only_id))) {			Node *gid = graph->get_node(itos(p_only_id));			if (gid) {				memdelete(gid);			}		}	} else {		for (int i = 0; i < graph->get_child_count(); i++) {			if (Object::cast_to<GraphNode>(graph->get_child(i))) {				memdelete(graph->get_child(i));				i--;			}		}	}	graph->show();	select_func_text->hide();	Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {		Control::get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("int"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("float"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("String"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("StringName"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedInt64Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedFloat64Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons"))	};	Ref<Texture2D> seq_port = Control::get_theme_icon(SNAME("VisualShaderPort"), SNAME("EditorIcons"));	List<int> node_ids;	script->get_node_list(&node_ids);	List<int> ids;	script->get_node_list(&ids);	StringName editor_icons = "EditorIcons";	for (int &E : ids) {		if (p_only_id >= 0 && p_only_id != E) {			continue;		}		Ref<VisualScriptNode> node = script->get_node(E);		Vector2 pos = script->get_node_position(E);		GraphNode *gnode = memnew(GraphNode);		gnode->set_title(node->get_caption());		gnode->set_position_offset(pos * EDSCALE);		if (error_line == E) {			gnode->set_overlay(GraphNode::OVERLAY_POSITION);		} else if (node->is_breakpoint()) {			gnode->set_overlay(GraphNode::OVERLAY_BREAKPOINT);		}		gnode->set_meta("__vnode", node);		gnode->set_name(itos(E));		gnode->connect("dragged", callable_mp(this, &VisualScriptEditor::_node_moved), varray(E));		gnode->connect("close_request", callable_mp(this, &VisualScriptEditor::_remove_node), varray(E), CONNECT_DEFERRED);		{			Ref<VisualScriptFunction> v = node;			if (!v.is_valid()) {				gnode->set_show_close_button(true);			}		}		bool has_gnode_text = false;		Ref<VisualScriptLists> nd_list = node;		bool is_vslist = nd_list.is_valid();		if (is_vslist) {			HBoxContainer *hbnc = memnew(HBoxContainer);			if (nd_list->is_input_port_editable()) {				has_gnode_text = true;				Button *btn = memnew(Button);				btn->set_text(TTR("Add Input Port"));				hbnc->add_child(btn);				btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_input_port), varray(E), CONNECT_DEFERRED);			}			if (nd_list->is_output_port_editable()) {				if (nd_list->is_input_port_editable()) {					hbnc->add_spacer();				}				has_gnode_text = true;				Button *btn = memnew(Button);				btn->set_text(TTR("Add Output Port"));				hbnc->add_child(btn);				btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_output_port), varray(E), CONNECT_DEFERRED);			}			gnode->add_child(hbnc);		} else if (Object::cast_to<VisualScriptExpression>(node.ptr())) {			has_gnode_text = true;			LineEdit *line_edit = memnew(LineEdit);			line_edit->set_text(node->get_text());			line_edit->set_expand_to_text_length_enabled(true);			line_edit->add_theme_font_override("font", get_theme_font(SNAME("source"), SNAME("EditorFonts")));			gnode->add_child(line_edit);			line_edit->connect("text_changed", callable_mp(this, &VisualScriptEditor::_expression_text_changed), varray(E));		} else {			String text = node->get_text();			if (!text.is_empty()) {				has_gnode_text = true;				Label *label = memnew(Label);				label->set_text(text);				gnode->add_child(label);			}		}		if (Object::cast_to<VisualScriptComment>(node.ptr())) {			Ref<VisualScriptComment> vsc = node;			gnode->set_comment(true);			gnode->set_resizable(true);			gnode->set_custom_minimum_size(vsc->get_size() * EDSCALE);			gnode->connect("resize_request", callable_mp(this, &VisualScriptEditor::_comment_node_resized), varray(E));		}		if (node_styles.has(node->get_category())) {			Ref<StyleBoxFlat> sbf = node_styles[node->get_category()];			if (gnode->is_comment()) {				sbf = EditorNode::get_singleton()->get_theme_base()->get_theme()->get_stylebox(SNAME("comment"), SNAME("GraphNode"));			}			Color c = sbf->get_border_color();			c = ((c.r + c.g + c.b) / 3) < 0.7 ? Color(1.0, 1.0, 1.0, 0.85) : Color(0.0, 0.0, 0.0, 0.85);			Color ic = c;			gnode->add_theme_color_override("title_color", c);			c.a = 1;			gnode->add_theme_color_override("close_color", c);			gnode->add_theme_color_override("resizer_color", ic);			gnode->add_theme_style_override("frame", sbf);		}		const Color mono_color = get_theme_color(SNAME("mono_color"), SNAME("Editor"));		int slot_idx = 0;		bool single_seq_output = node->get_output_sequence_port_count() == 1 && node->get_output_sequence_port_text(0) == String();		if ((node->has_input_sequence_port() || single_seq_output) || has_gnode_text) {			// IF has_gnode_text is true BUT we have no sequence ports to draw (in here),			// we still draw the disabled default ones to shift up the slots by one,			// so the slots DON'T start with the content text.			// IF has_gnode_text is false, but we DO want to draw default sequence ports,			// we draw a dummy text to take up the position of the sequence nodes, so all the other ports are still aligned correctly.			if (!has_gnode_text) {				Label *dummy = memnew(Label);				dummy->set_text(" ");				gnode->add_child(dummy);			}			gnode->set_slot(0, node->has_input_sequence_port(), TYPE_SEQUENCE, mono_color, single_seq_output, TYPE_SEQUENCE, mono_color, seq_port, seq_port);			slot_idx++;		}		int mixed_seq_ports = 0;		if (!single_seq_output) {			if (node->has_mixed_input_and_sequence_ports()) {				mixed_seq_ports = node->get_output_sequence_port_count();			} else {				for (int i = 0; i < node->get_output_sequence_port_count(); i++) {					Label *text2 = memnew(Label);					text2->set_text(node->get_output_sequence_port_text(i));					text2->set_align(Label::ALIGN_RIGHT);					gnode->add_child(text2);					gnode->set_slot(slot_idx, false, 0, Color(), true, TYPE_SEQUENCE, mono_color, seq_port, seq_port);					slot_idx++;				}			}		}		for (int i = 0; i < MAX(node->get_output_value_port_count(), MAX(mixed_seq_ports, node->get_input_value_port_count())); i++) {			bool left_ok = false;			Variant::Type left_type = Variant::NIL;			String left_name;			if (i < node->get_input_value_port_count()) {				PropertyInfo pi = node->get_input_value_port_info(i);				left_ok = true;				left_type = pi.type;				left_name = pi.name;			}			bool right_ok = false;			Variant::Type right_type = Variant::NIL;			String right_name;			if (i >= mixed_seq_ports && i < node->get_output_value_port_count() + mixed_seq_ports) {				PropertyInfo pi = node->get_output_value_port_info(i - mixed_seq_ports);				right_ok = true;				right_type = pi.type;				right_name = pi.name;			}			VBoxContainer *vbc = memnew(VBoxContainer);			HBoxContainer *hbc = memnew(HBoxContainer);			HBoxContainer *hbc2 = memnew(HBoxContainer);			vbc->add_child(hbc);			vbc->add_child(hbc2);			if (left_ok) {				Ref<Texture2D> t;				if (left_type >= 0 && left_type < Variant::VARIANT_MAX) {					t = type_icons[left_type];				}				if (t.is_valid()) {					TextureRect *tf = memnew(TextureRect);					tf->set_texture(t);					tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);					hbc->add_child(tf);				}				if (is_vslist) {					if (nd_list->is_input_port_name_editable()) {						LineEdit *name_box = memnew(LineEdit);						hbc->add_child(name_box);						name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));						name_box->set_text(left_name);						name_box->set_expand_to_text_length_enabled(true);						name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E));						name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E, i, true));					} else {						hbc->add_child(memnew(Label(left_name)));					}					if (nd_list->is_input_port_type_editable()) {						OptionButton *opbtn = memnew(OptionButton);						for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {							opbtn->add_item(Variant::get_type_name(Variant::Type(j)));						}						opbtn->select(left_type);						opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));						hbc->add_child(opbtn);						opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E, i, true), CONNECT_DEFERRED);					}					Button *rmbtn = memnew(Button);					rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));					hbc->add_child(rmbtn);					rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_input_port), varray(E, i), CONNECT_DEFERRED);				} else {					hbc->add_child(memnew(Label(left_name)));				}				if (left_type != Variant::NIL && !script->is_input_value_port_connected(E, i)) {					PropertyInfo pi = node->get_input_value_port_info(i);					Button *button = memnew(Button);					Variant value = node->get_default_input_value(i);					if (value.get_type() != left_type) {						//different type? for now convert						//not the same, reconvert						Callable::CallError ce;						const Variant *existingp = &value;						Variant::construct(left_type, value, &existingp, 1, ce);					}					if (left_type == Variant::COLOR) {						button->set_custom_minimum_size(Size2(30, 0) * EDSCALE);						button->connect("draw", callable_mp(this, &VisualScriptEditor::_draw_color_over_button), varray(button, value));					} else if (left_type == Variant::OBJECT && Ref<Resource>(value).is_valid()) {						Ref<Resource> res = value;						Array arr;						arr.push_back(button->get_instance_id());						arr.push_back(String(value));						EditorResourcePreview::get_singleton()->queue_edited_resource_preview(res, this, "_button_resource_previewed", arr);					} else if (pi.type == Variant::INT && pi.hint == PROPERTY_HINT_ENUM) {						button->set_text(pi.hint_string.get_slice(",", value));					} else {						button->set_text(value);					}					button->connect("pressed", callable_mp(this, &VisualScriptEditor::_default_value_edited), varray(button, E, i));					hbc2->add_child(button);				}			} else {				Control *c = memnew(Control);				c->set_custom_minimum_size(Size2(10, 0) * EDSCALE);				hbc->add_child(c);			}			hbc->add_spacer();			hbc2->add_spacer();			if (i < mixed_seq_ports) {				Label *text2 = memnew(Label);				text2->set_text(node->get_output_sequence_port_text(i));				text2->set_align(Label::ALIGN_RIGHT);				hbc->add_child(text2);			}			if (right_ok) {				if (is_vslist) {					Button *rmbtn = memnew(Button);					rmbtn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));					hbc->add_child(rmbtn);					rmbtn->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_output_port), varray(E, i), CONNECT_DEFERRED);					if (nd_list->is_output_port_type_editable()) {						OptionButton *opbtn = memnew(OptionButton);						for (int j = Variant::NIL; j < Variant::VARIANT_MAX; j++) {							opbtn->add_item(Variant::get_type_name(Variant::Type(j)));						}						opbtn->select(right_type);						opbtn->set_custom_minimum_size(Size2(100 * EDSCALE, 0));						hbc->add_child(opbtn);						opbtn->connect("item_selected", callable_mp(this, &VisualScriptEditor::_change_port_type), varray(E, i, false), CONNECT_DEFERRED);					}					if (nd_list->is_output_port_name_editable()) {						LineEdit *name_box = memnew(LineEdit);						hbc->add_child(name_box);						name_box->set_custom_minimum_size(Size2(60 * EDSCALE, 0));						name_box->set_text(right_name);						name_box->set_expand_to_text_length_enabled(true);						name_box->connect("resized", callable_mp(this, &VisualScriptEditor::_update_node_size), varray(E));						name_box->connect("focus_exited", callable_mp(this, &VisualScriptEditor::_port_name_focus_out), varray(name_box, E, i, false));					} else {						hbc->add_child(memnew(Label(right_name)));					}				} else {					hbc->add_child(memnew(Label(right_name)));				}				Ref<Texture2D> t;				if (right_type >= 0 && right_type < Variant::VARIANT_MAX) {					t = type_icons[right_type];				}				if (t.is_valid()) {					TextureRect *tf = memnew(TextureRect);					tf->set_texture(t);					tf->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);					hbc->add_child(tf);				}			}			gnode->add_child(vbc);			bool dark_theme = get_theme_constant(SNAME("dark_theme"), SNAME("Editor"));			if (i < mixed_seq_ports) {				gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), true, TYPE_SEQUENCE, mono_color, Ref<Texture2D>(), seq_port);			} else {				gnode->set_slot(slot_idx, left_ok, left_type, _color_from_type(left_type, dark_theme), right_ok, right_type, _color_from_type(right_type, dark_theme));			}			slot_idx++;		}		graph->add_child(gnode);		if (gnode->is_comment()) {			graph->move_child(gnode, 0);		}	}	_update_graph_connections();	float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");	graph->set_minimap_opacity(graph_minimap_opacity);	// Use default_func instead of default_func for now I think that should be good stop gap solution to ensure not breaking anything.	graph->call_deferred(SNAME("set_scroll_ofs"), script->get_scroll() * EDSCALE);	updating_graph = false;}void VisualScriptEditor::_change_port_type(int p_select, int p_id, int p_port, bool is_input) {	Ref<VisualScriptLists> vsn = script->get_node(p_id);	if (!vsn.is_valid()) {		return;	}	undo_redo->create_action(TTR("Change Port Type"));	if (is_input) {		undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_type", p_port, Variant::Type(p_select));		undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_type", p_port, vsn->get_input_value_port_info(p_port).type);	} else {		undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_type", p_port, Variant::Type(p_select));		undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_type", p_port, vsn->get_output_value_port_info(p_port).type);	}	undo_redo->commit_action();}void VisualScriptEditor::_update_node_size(int p_id) {	Node *node = graph->get_node(itos(p_id));	if (Object::cast_to<Control>(node)) {		Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller.	}}void VisualScriptEditor::_port_name_focus_out(const Node *p_name_box, int p_id, int p_port, bool is_input) {	Ref<VisualScriptLists> vsn = script->get_node(p_id);	if (!vsn.is_valid()) {		return;	}	String text;	if (Object::cast_to<LineEdit>(p_name_box)) {		text = Object::cast_to<LineEdit>(p_name_box)->get_text();	} else {		return;	}	undo_redo->create_action(TTR("Change Port Name"));	if (is_input) {		undo_redo->add_do_method(vsn.ptr(), "set_input_data_port_name", p_port, text);		undo_redo->add_undo_method(vsn.ptr(), "set_input_data_port_name", p_port, vsn->get_input_value_port_info(p_port).name);	} else {		undo_redo->add_do_method(vsn.ptr(), "set_output_data_port_name", p_port, text);		undo_redo->add_undo_method(vsn.ptr(), "set_output_data_port_name", p_port, vsn->get_output_value_port_info(p_port).name);	}	undo_redo->commit_action();}void VisualScriptEditor::_update_members() {	ERR_FAIL_COND(!script.is_valid());	updating_members = true;	members->clear();	TreeItem *root = members->create_item();	TreeItem *functions = members->create_item(root);	functions->set_selectable(0, false);	functions->set_text(0, TTR("Functions:"));	functions->add_button(0, Control::get_theme_icon(SNAME("Override"), SNAME("EditorIcons")), 1, false, TTR("Override an existing built-in function."));	functions->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), 0, false, TTR("Create a new function."));	functions->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor")));	List<StringName> func_names;	script->get_function_list(&func_names);	func_names.sort_custom<StringName::AlphCompare>();	for (const StringName &E : func_names) {		TreeItem *ti = members->create_item(functions);		ti->set_text(0, E);		ti->set_selectable(0, true);		ti->set_metadata(0, E);		ti->add_button(0, Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons")), 0);		if (selected == E) {			ti->select(0);		}	}	TreeItem *variables = members->create_item(root);	variables->set_selectable(0, false);	variables->set_text(0, TTR("Variables:"));	variables->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), -1, false, TTR("Create a new variable."));	variables->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor")));	Ref<Texture2D> type_icons[Variant::VARIANT_MAX] = {		Control::get_theme_icon(SNAME("Variant"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("bool"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("int"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("float"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("String"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector2"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector2i"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Rect2"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Rect2i"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector3"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Vector3i"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Transform2D"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Plane"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Quaternion"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("AABB"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Basis"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Transform3D"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Color"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("NodePath"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("RID"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("MiniObject"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Callable"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Signal"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Dictionary"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedByteArray"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedInt32Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedFloat32Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedStringArray"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedVector2Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedVector3Array"), SNAME("EditorIcons")),		Control::get_theme_icon(SNAME("PackedColorArray"), SNAME("EditorIcons"))	};	List<StringName> var_names;	script->get_variable_list(&var_names);	for (const StringName &E : var_names) {		TreeItem *ti = members->create_item(variables);		ti->set_text(0, E);		ti->set_suffix(0, "= " + _sanitized_variant_text(E));		ti->set_icon(0, type_icons[script->get_variable_info(E).type]);		ti->set_selectable(0, true);		ti->set_editable(0, true);		ti->set_metadata(0, E);		if (selected == E) {			ti->select(0);		}	}	TreeItem *_signals = members->create_item(root);	_signals->set_selectable(0, false);	_signals->set_text(0, TTR("Signals:"));	_signals->add_button(0, Control::get_theme_icon(SNAME("Add"), SNAME("EditorIcons")), -1, false, TTR("Create a new signal."));	_signals->set_custom_color(0, Control::get_theme_color(SNAME("mono_color"), SNAME("Editor")));	List<StringName> signal_names;	script->get_custom_signal_list(&signal_names);	for (const StringName &E : signal_names) {		TreeItem *ti = members->create_item(_signals);		ti->set_text(0, E);		ti->set_selectable(0, true);		ti->set_editable(0, true);		ti->set_metadata(0, E);		if (selected == E) {			ti->select(0);		}	}	String base_type = script->get_instance_base_type();	String icon_type = base_type;	if (!Control::has_theme_icon(base_type, SNAME("EditorIcons"))) {		icon_type = "Object";	}	base_type_select->set_text(base_type);	base_type_select->set_icon(Control::get_theme_icon(icon_type, SNAME("EditorIcons")));	updating_members = false;}String VisualScriptEditor::_sanitized_variant_text(const StringName &property_name) {	Variant var = script->get_variable_default_value(property_name);	if (script->get_variable_info(property_name).type != Variant::NIL) {		Callable::CallError ce;		const Variant *converted = &var;		Variant n;		Variant::construct(script->get_variable_info(property_name).type, n, &converted, 1, ce);		var = n;	}	return String(var);}void VisualScriptEditor::_member_selected() {	if (updating_members) {		return;	}	TreeItem *ti = members->get_selected();	ERR_FAIL_COND(!ti);	selected = ti->get_metadata(0);	if (ti->get_parent() == members->get_root()->get_first_child()) {#ifdef OSX_ENABLED		bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_META);#else		bool held_ctrl = Input::get_singleton()->is_key_pressed(KEY_CTRL);#endif		if (held_ctrl) {			ERR_FAIL_COND(!script->has_function(selected));			_center_on_node(script->get_function_node_id(selected));		}	}}void VisualScriptEditor::_member_edited() {	if (updating_members) {		return;	}	TreeItem *ti = members->get_edited();	ERR_FAIL_COND(!ti);	String name = ti->get_metadata(0);	String new_name = ti->get_text(0);	if (name == new_name) {		return;	}	if (!new_name.is_valid_identifier()) {		EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name);		updating_members = true;		ti->set_text(0, name);		updating_members = false;		return;	}	if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {		EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name);		updating_members = true;		ti->set_text(0, name);		updating_members = false;		return;	}	TreeItem *root = members->get_root();	if (ti->get_parent() == root->get_first_child()) {		selected = new_name;		int node_id = script->get_function_node_id(name);		Ref<VisualScriptFunction> func;		if (script->has_node(node_id)) {			func = script->get_node(node_id);		}		undo_redo->create_action(TTR("Rename Function"));		undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);		undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name);		if (func.is_valid()) {			undo_redo->add_do_method(func.ptr(), "set_name", new_name);			undo_redo->add_undo_method(func.ptr(), "set_name", name);		}		// Also fix all function calls.		List<int> lst;		script->get_node_list(&lst);		for (int &F : lst) {			Ref<VisualScriptFunctionCall> fncall = script->get_node(F);			if (!fncall.is_valid()) {				continue;			}			if (fncall->get_function() == name) {				undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);				undo_redo->add_undo_method(fncall.ptr(), "set_function", name);			}		}		undo_redo->add_do_method(this, "_update_members");		undo_redo->add_undo_method(this, "_update_members");		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");		undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");		undo_redo->commit_action();		return; // Or crash because it will become invalid.	}	if (ti->get_parent() == root->get_first_child()->get_next()) {		selected = new_name;		undo_redo->create_action(TTR("Rename Variable"));		undo_redo->add_do_method(script.ptr(), "rename_variable", name, new_name);		undo_redo->add_undo_method(script.ptr(), "rename_variable", new_name, name);		undo_redo->add_do_method(this, "_update_members");		undo_redo->add_undo_method(this, "_update_members");		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");		undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");		undo_redo->commit_action();		return; // Or crash because it will become invalid.	}	if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {		selected = new_name;		undo_redo->create_action(TTR("Rename Signal"));		undo_redo->add_do_method(script.ptr(), "rename_custom_signal", name, new_name);		undo_redo->add_undo_method(script.ptr(), "rename_custom_signal", new_name, name);		undo_redo->add_do_method(this, "_update_members");		undo_redo->add_undo_method(this, "_update_members");		undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");		undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");		undo_redo->commit_action();		return; // Or crash because it will become invalid.	}}void VisualScriptEditor::_create_function_dialog() {	function_create_dialog->popup_centered();	func_name_box->set_text("");	func_name_box->grab_focus();	for (int i = 0; i < func_input_vbox->get_child_count(); i++) {		Node *nd = func_input_vbox->get_child(i);		nd->queue_delete();	}}void VisualScriptEditor::_create_function() {	String name = _validate_name((func_name_box->get_text() == "") ? "new_func" : func_name_box->get_text());	selected = name;	Vector2 pos = _get_available_pos();	Ref<VisualScriptFunction> func_node;	func_node.instantiate();	func_node->set_name(name);	for (int i = 0; i < func_input_vbox->get_child_count(); i++) {		OptionButton *opbtn = Object::cast_to<OptionButton>(func_input_vbox->get_child(i)->get_child(3));		LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1));		if (!opbtn || !lne) {			continue;		}		Variant::Type arg_type = Variant::Type(opbtn->get_selected());		String arg_name = lne->get_text();		func_node->add_argument(arg_type, arg_name);	}	int func_node_id = script->get_available_id();	undo_redo->create_action(TTR("Add Function"));	undo_redo->add_do_method(script.ptr(), "add_function", name, func_node_id);	undo_redo->add_undo_method(script.ptr(), "remove_function", name);	undo_redo->add_do_method(script.ptr(), "add_node", func_node_id, func_node, pos);	undo_redo->add_undo_method(script.ptr(), "remove_node", func_node_id);	undo_redo->add_do_method(this, "_update_members");	undo_redo->add_undo_method(this, "_update_members");	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");	undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");	undo_redo->commit_action();	_update_graph();}void VisualScriptEditor::_add_node_dialog() {	_generic_search(script->get_instance_base_type(), graph->get_global_position() + Vector2(55, 80), true);}void VisualScriptEditor::_add_func_input() {	HBoxContainer *hbox = memnew(HBoxContainer);	hbox->set_h_size_flags(SIZE_EXPAND_FILL);	Label *name_label = memnew(Label);	name_label->set_text(TTR("Name:"));	hbox->add_child(name_label);	LineEdit *name_box = memnew(LineEdit);	name_box->set_h_size_flags(SIZE_EXPAND_FILL);	name_box->set_text("input");	name_box->connect("focus_entered", callable_mp(this, &VisualScriptEditor::_deselect_input_names));	hbox->add_child(name_box);	Label *type_label = memnew(Label);	type_label->set_text(TTR("Type:"));	hbox->add_child(type_label);	OptionButton *type_box = memnew(OptionButton);	type_box->set_custom_minimum_size(Size2(120 * EDSCALE, 0));	for (int i = Variant::NIL; i < Variant::VARIANT_MAX; i++) {		type_box->add_item(Variant::get_type_name(Variant::Type(i)));	}	type_box->select(1);	hbox->add_child(type_box);	Button *delete_button = memnew(Button);	delete_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("Remove"), SNAME("EditorIcons")));	delete_button->set_tooltip(vformat(TTR("Delete input port")));	hbox->add_child(delete_button);	for (int i = 0; i < func_input_vbox->get_child_count(); i++) {		LineEdit *line_edit = (LineEdit *)func_input_vbox->get_child(i)->get_child(1);		line_edit->deselect();	}	func_input_vbox->add_child(hbox);	hbox->set_meta("id", hbox->get_index());	delete_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_remove_func_input), varray(hbox));	name_box->select_all();	name_box->grab_focus();}void VisualScriptEditor::_remove_func_input(Node *p_node) {	func_input_vbox->remove_child(p_node);	p_node->queue_delete();}void VisualScriptEditor::_deselect_input_names() {	int cn = func_input_vbox->get_child_count();	for (int i = 0; i < cn; i++) {		LineEdit *lne = Object::cast_to<LineEdit>(func_input_vbox->get_child(i)->get_child(1));		if (lne) {			lne->deselect();		}	}}void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_button) {	TreeItem *ti = Object::cast_to<TreeItem>(p_item);	TreeItem *root = members->get_root();	if (ti->get_parent() == root) {		//main buttons		if (ti == root->get_first_child()) {			// Add function, this one uses menu.			if (p_button == 1) {				// Ensure script base exists otherwise use custom base type.				ERR_FAIL_COND(script.is_null());				new_virtual_method_select->select_method_from_base_type(script->get_instance_base_type(), String(), true);				return;			} else if (p_button == 0) {				String name = _validate_name("new_function");				selected = name;				Vector2 pos = _get_available_pos();				Ref<VisualScriptFunction> func_node;				func_node.instantiate();				func_node->set_name(name);				int fn_id = script->get_available_id();				undo_redo->create_action(TTR("Add Function"));				undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id);				undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos);				undo_redo->add_undo_method(script.ptr(), "remove_function", name);				undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);				undo_redo->add_do_method(this, "_update_members");				undo_redo->add_undo_method(this, "_update_members");				undo_redo->add_do_method(this, "_update_graph");				undo_redo->add_undo_method(this, "_update_graph");				undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");				undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");				undo_redo->commit_action();				_update_graph();			}			return; // Or crash because it will become invalid.		}		if (ti == root->get_first_child()->get_next()) {			// Add variable.			String name = _validate_name("new_variable");			selected = name;			undo_redo->create_action(TTR("Add Variable"));			undo_redo->add_do_method(script.ptr(), "add_variable", name);			undo_redo->add_undo_method(script.ptr(), "remove_variable", name);			undo_redo->add_do_method(this, "_update_members");			undo_redo->add_undo_method(this, "_update_members");			undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");			undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");			undo_redo->commit_action();			return; // Or crash because it will become invalid.		}		if (ti == root->get_first_child()->get_next()->get_next()) {			// Add variable.			String name = _validate_name("new_signal");			selected = name;			undo_redo->create_action(TTR("Add Signal"));			undo_redo->add_do_method(script.ptr(), "add_custom_signal", name);			undo_redo->add_undo_method(script.ptr(), "remove_custom_signal", name);			undo_redo->add_do_method(this, "_update_members");			undo_redo->add_undo_method(this, "_update_members");			undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");			undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");			undo_redo->commit_action();			return; // Or crash because it will become invalid.		}	} else if (ti->get_parent() == root->get_first_child()) {		selected = ti->get_text(0);		function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));		function_name_edit->popup();		function_name_box->set_text(selected);		function_name_box->select_all();	}}void VisualScriptEditor::_add_input_port(int p_id) {	Ref<VisualScriptLists> vsn = script->get_node(p_id);	if (!vsn.is_valid()) {		return;	}	updating_graph = true;	undo_redo->create_action(TTR("Add Input Port"), UndoRedo::MERGE_ENDS);	undo_redo->add_do_method(vsn.ptr(), "add_input_data_port", Variant::NIL, "arg", -1);	undo_redo->add_do_method(this, "_update_graph", p_id);	undo_redo->add_undo_method(vsn.ptr(), "remove_input_data_port", vsn->get_input_value_port_count());	undo_redo->add_undo_method(this, "_update_graph", p_id);	updating_graph = false;	undo_redo->commit_action();}void VisualScriptEditor::_add_output_port(int p_id) {	Ref<VisualScriptLists> vsn = script->get_node(p_id);	if (!vsn.is_valid()) {		return;	}	updating_graph = true;	undo_redo->create_action(TTR("Add Output Port"), UndoRedo::MERGE_ENDS);	undo_redo->add_do_method(vsn.ptr(), "add_output_data_port", Variant::NIL, "arg", -1);	undo_redo->add_do_method(this, "_update_graph", p_id);	undo_redo->add_undo_method(vsn.ptr(), "remove_output_data_port", vsn->get_output_value_port_count());	undo_redo->add_undo_method(this, "_update_graph", p_id);	updating_graph = false;	undo_redo->commit_action();}void VisualScriptEditor::_remove_input_port(int p_id, int p_port) {	Ref<VisualScriptLists> vsn = script->get_node(p_id);	if (!vsn.is_valid()) {		return;	}	updating_graph = true;	undo_redo->create_action(TTR("Remove Input Port"), UndoRedo::MERGE_ENDS);	int conn_from = -1, conn_port = -1;	script->get_input_value_port_connection_source(p_id, p_port, &conn_from, &conn_port);	if (conn_from != -1) {		undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_id, p_port);	}	undo_redo->add_do_method(vsn.ptr(), "remove_input_data_port", p_port);	undo_redo->add_do_method(this, "_update_graph", p_id);	if (conn_from != -1) {		undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_id, p_port);	}	undo_redo->add_undo_method(vsn.ptr(), "add_input_data_port", vsn->get_input_value_port_info(p_port).type, vsn->get_input_value_port_info(p_port).name, p_port);	undo_redo->add_undo_method(this, "_update_graph", p_id);	updating_graph = false;	undo_redo->commit_action();}void VisualScriptEditor::_remove_output_port(int p_id, int p_port) {	Ref<VisualScriptLists> vsn = script->get_node(p_id);	if (!vsn.is_valid()) {		return;	}	updating_graph = true;	undo_redo->create_action(TTR("Remove Output Port"), UndoRedo::MERGE_ENDS);	List<VisualScript::DataConnection> data_connections;	script->get_data_connection_list(&data_connections);	HashMap<int, Set<int>> conn_map;	for (const VisualScript::DataConnection &E : data_connections) {		if (E.from_node == p_id && E.from_port == p_port) {			// Push into the connections map.			if (!conn_map.has(E.to_node)) {				conn_map.set(E.to_node, Set<int>());			}			conn_map[E.to_node].insert(E.to_port);		}	}	undo_redo->add_do_method(vsn.ptr(), "remove_output_data_port", p_port);	undo_redo->add_do_method(this, "_update_graph", p_id);	List<int> keys;	conn_map.get_key_list(&keys);	for (const int &E : keys) {		for (const Set<int>::Element *F = conn_map[E].front(); F; F = F->next()) {			undo_redo->add_undo_method(script.ptr(), "data_connect", p_id, p_port, E, F);		}	}	undo_redo->add_undo_method(vsn.ptr(), "add_output_data_port", vsn->get_output_value_port_info(p_port).type, vsn->get_output_value_port_info(p_port).name, p_port);	undo_redo->add_undo_method(this, "_update_graph", p_id);	updating_graph = false;	undo_redo->commit_action();}void VisualScriptEditor::_expression_text_changed(const String &p_text, int p_id) {	Ref<VisualScriptExpression> vse = script->get_node(p_id);	if (!vse.is_valid()) {		return;	}	updating_graph = true;	undo_redo->create_action(TTR("Change Expression"), UndoRedo::MERGE_ENDS);	undo_redo->add_do_property(vse.ptr(), "expression", p_text);	undo_redo->add_undo_property(vse.ptr(), "expression", vse->get("expression"));	undo_redo->add_do_method(this, "_update_graph", p_id);	undo_redo->add_undo_method(this, "_update_graph", p_id);	undo_redo->commit_action();	Node *node = graph->get_node(itos(p_id));	if (Object::cast_to<Control>(node)) {		Object::cast_to<Control>(node)->set_size(Vector2(1, 1)); // Shrink if text is smaller.	}	updating_graph = false;}Vector2 VisualScriptEditor::_get_pos_in_graph(Vector2 p_point) const {	Vector2 pos = (graph->get_scroll_ofs() + p_point) / (graph->get_zoom() * EDSCALE);	if (graph->is_using_snap()) {		int snap = graph->get_snap();		pos = pos.snapped(Vector2(snap, snap));	}	return pos;}Vector2 VisualScriptEditor::_get_available_pos(bool p_centered, Vector2 p_pos) const {	if (p_centered) {		p_pos = _get_pos_in_graph(graph->get_size() * 0.5);	}	while (true) {		bool exists = false;		List<int> existing;		script->get_node_list(&existing);		for (int &E : existing) {			Point2 pos = script->get_node_position(E);			if (pos.distance_to(p_pos) < 50) {				p_pos += Vector2(graph->get_snap(), graph->get_snap());				exists = true;				break;			}		}		if (exists) {			continue;		}		break;	}	return p_pos;}String VisualScriptEditor::_validate_name(const String &p_name) const {	String valid = p_name;	int counter = 1;	while (true) {		bool exists = script->has_function(valid) || script->has_variable(valid) || script->has_custom_signal(valid);		if (exists) {			counter++;			valid = p_name + "_" + itos(counter);			continue;		}		break;	}	return valid;}void VisualScriptEditor::_on_nodes_delete() {	// Delete all the selected nodes.	List<int> to_erase;	for (int i = 0; i < graph->get_child_count(); i++) {		GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));		if (gn) {			if (gn->is_selected() && gn->is_close_button_visible()) {				to_erase.push_back(gn->get_name().operator String().to_int());			}		}	}	if (to_erase.is_empty()) {		return;	}	undo_redo->create_action(TTR("Remove VisualScript Nodes"));	for (int &F : to_erase) {		int cr_node = F;		undo_redo->add_do_method(script.ptr(), "remove_node", cr_node);		undo_redo->add_undo_method(script.ptr(), "add_node", cr_node, script->get_node(cr_node), script->get_node_position(cr_node));		List<VisualScript::SequenceConnection> sequence_conns;		script->get_sequence_connection_list(&sequence_conns);		for (const VisualScript::SequenceConnection &E : sequence_conns) {			if (E.from_node == cr_node || E.to_node == cr_node) {				undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node);			}		}		List<VisualScript::DataConnection> data_conns;		script->get_data_connection_list(&data_conns);		for (const VisualScript::DataConnection &E : data_conns) {			if (E.from_node == F || E.to_node == F) {				undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port);			}		}	}	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->commit_action();}void VisualScriptEditor::_on_nodes_duplicate() {	Set<int> to_duplicate;	for (int i = 0; i < graph->get_child_count(); i++) {		GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));		if (gn) {			if (gn->is_selected() && gn->is_close_button_visible()) {				int id = gn->get_name().operator String().to_int();				to_duplicate.insert(id);			}		}	}	if (to_duplicate.is_empty()) {		return;	}	undo_redo->create_action(TTR("Duplicate VisualScript Nodes"));	int idc = script->get_available_id() + 1;	Set<int> to_select;	HashMap<int, int> remap;	for (Set<int>::Element *F = to_duplicate.front(); F; F = F->next()) {		// Duplicate from the specific function but place it into the default func as it would lack the connections.		Ref<VisualScriptNode> node = script->get_node(F->get());		Ref<VisualScriptNode> dupe = node->duplicate(true);		int new_id = idc++;		remap.set(F->get(), new_id);		to_select.insert(new_id);		undo_redo->add_do_method(script.ptr(), "add_node", new_id, dupe, script->get_node_position(F->get()) + Vector2(20, 20));		undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);	}	List<VisualScript::SequenceConnection> seqs;	script->get_sequence_connection_list(&seqs);	for (const VisualScript::SequenceConnection &E : seqs) {		if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) {			undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E.from_node], E.from_output, remap[E.to_node]);		}	}	List<VisualScript::DataConnection> data;	script->get_data_connection_list(&data);	for (const VisualScript::DataConnection &E : data) {		if (to_duplicate.has(E.from_node) && to_duplicate.has(E.to_node)) {			undo_redo->add_do_method(script.ptr(), "data_connect", remap[E.from_node], E.from_port, remap[E.to_node], E.to_port);		}	}	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->commit_action();	for (int i = 0; i < graph->get_child_count(); i++) {		GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));		if (gn) {			int id = gn->get_name().operator String().to_int();			gn->set_selected(to_select.has(id));		}	}	if (to_select.size()) {		EditorNode::get_singleton()->push_item(script->get_node(to_select.front()->get()).ptr());	}}void VisualScriptEditor::_generic_search(String p_base_type, Vector2 pos, bool node_centered) {	if (node_centered) {		port_action_pos = graph->get_size() / 2.0f;	} else {		port_action_pos = graph->get_viewport()->get_mouse_position() - graph->get_global_position();	}	new_connect_node_select->select_from_visual_script(p_base_type, false, false); // neither connecting nor reset text	// Ensure that the dialog fits inside the graph.	Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();	pos.x = pos.x > bounds.x ? bounds.x : pos.x;	pos.y = pos.y > bounds.y ? bounds.y : pos.y;	if (pos != Vector2()) {		new_connect_node_select->set_position(pos);	}}void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {	ERR_FAIL_COND(p_event.is_null());	// GUI input for VS Editor Plugin	Ref<InputEventMouseButton> key = p_event;	if (key.is_valid() && !key->is_pressed()) {		mouse_up_position = Input::get_singleton()->get_mouse_position();	}}void VisualScriptEditor::_graph_gui_input(const Ref<InputEvent> &p_event) {	Ref<InputEventMouseButton> key = p_event;	if (key.is_valid() && key->is_pressed() && key->get_button_mask() == MOUSE_BUTTON_RIGHT) {		saved_position = graph->get_local_mouse_position();		Point2 gpos = Input::get_singleton()->get_mouse_position();		_generic_search(script->get_instance_base_type(), gpos);	}}void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {	Ref<InputEventKey> key = p_event;	if (key.is_valid() && key->is_pressed() && !key->is_echo()) {		if (members->has_focus()) {			TreeItem *ti = members->get_selected();			if (ti) {				TreeItem *root = members->get_root();				if (ti->get_parent() == root->get_first_child()) {					member_type = MEMBER_FUNCTION;				}				if (ti->get_parent() == root->get_first_child()->get_next()) {					member_type = MEMBER_VARIABLE;				}				if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {					member_type = MEMBER_SIGNAL;				}				member_name = ti->get_text(0);			}			if (ED_IS_SHORTCUT("ui_graph_delete", p_event)) {				_member_option(MEMBER_REMOVE);			}			if (ED_IS_SHORTCUT("visual_script_editor/edit_member", p_event)) {				_member_option(MEMBER_EDIT);			}		}	}	Ref<InputEventMouseButton> btn = p_event;	if (btn.is_valid() && btn->is_double_click()) {		TreeItem *ti = members->get_selected();		if (ti && ti->get_parent() == members->get_root()->get_first_child()) { // to check if it's a function			_center_on_node(script->get_function_node_id(ti->get_metadata(0)));		}	}}void VisualScriptEditor::_rename_function(const String &name, const String &new_name) {	if (!new_name.is_valid_identifier()) {		EditorNode::get_singleton()->show_warning(TTR("Name is not a valid identifier:") + " " + new_name);		return;	}	if (script->has_function(new_name) || script->has_variable(new_name) || script->has_custom_signal(new_name)) {		EditorNode::get_singleton()->show_warning(TTR("Name already in use by another func/var/signal:") + " " + new_name);		return;	}	int node_id = script->get_function_node_id(name);	Ref<VisualScriptFunction> func;	if (script->has_node(node_id)) {		func = script->get_node(node_id);	}	undo_redo->create_action(TTR("Rename Function"));	undo_redo->add_do_method(script.ptr(), "rename_function", name, new_name);	undo_redo->add_undo_method(script.ptr(), "rename_function", new_name, name);	if (func.is_valid()) {		undo_redo->add_do_method(func.ptr(), "set_name", new_name);		undo_redo->add_undo_method(func.ptr(), "set_name", name);	}	// Also fix all function calls.	List<int> lst;	script->get_node_list(&lst);	for (int &F : lst) {		Ref<VisualScriptFunctionCall> fncall = script->get_node(F);		if (!fncall.is_valid()) {			continue;		}		if (fncall->get_function() == name) {			undo_redo->add_do_method(fncall.ptr(), "set_function", new_name);			undo_redo->add_undo_method(fncall.ptr(), "set_function", name);		}	}	undo_redo->add_do_method(this, "_update_members");	undo_redo->add_undo_method(this, "_update_members");	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");	undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");	undo_redo->commit_action();}void VisualScriptEditor::_fn_name_box_input(const Ref<InputEvent> &p_event) {	if (!function_name_edit->is_visible()) {		return;	}	Ref<InputEventKey> key = p_event;	if (key.is_valid() && key->is_pressed() && key->get_keycode() == KEY_ENTER) {		function_name_edit->hide();		_rename_function(selected, function_name_box->get_text());		function_name_box->clear();	}}Variant VisualScriptEditor::get_drag_data_fw(const Point2 &p_point, Control *p_from) {	if (p_from == members) {		TreeItem *it = members->get_item_at_position(p_point);		if (!it) {			return Variant();		}		String type = it->get_metadata(0);		if (type == String()) {			return Variant();		}		Dictionary dd;		TreeItem *root = members->get_root();		if (it->get_parent() == root->get_first_child()) {			dd["type"] = "visual_script_function_drag";			dd["function"] = type;		} else if (it->get_parent() == root->get_first_child()->get_next()) {			dd["type"] = "visual_script_variable_drag";			dd["variable"] = type;		} else if (it->get_parent() == root->get_first_child()->get_next()->get_next()) {			dd["type"] = "visual_script_signal_drag";			dd["signal"] = type;		} else {			return Variant();		}		Label *label = memnew(Label);		label->set_text(it->get_text(0));		set_drag_preview(label);		return dd;	}	return Variant();}bool VisualScriptEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {	if (p_from == graph) {		Dictionary d = p_data;		if (d.has("type") &&				(String(d["type"]) == "visual_script_node_drag" ||						String(d["type"]) == "visual_script_function_drag" ||						String(d["type"]) == "visual_script_variable_drag" ||						String(d["type"]) == "visual_script_signal_drag" ||						String(d["type"]) == "obj_property" ||						String(d["type"]) == "resource" ||						String(d["type"]) == "files" ||						String(d["type"]) == "nodes")) {			if (String(d["type"]) == "obj_property") {#ifdef OSX_ENABLED				const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Getter. Hold Shift to drop a generic signature."), find_keycode_name(KEY_META)));#else				const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Getter. Hold Shift to drop a generic signature."));#endif			}			if (String(d["type"]) == "nodes") {#ifdef OSX_ENABLED				const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a simple reference to the node."), find_keycode_name(KEY_META)));#else				const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a simple reference to the node."));#endif			}			if (String(d["type"]) == "visual_script_variable_drag") {#ifdef OSX_ENABLED				const_cast<VisualScriptEditor *>(this)->_show_hint(vformat(TTR("Hold %s to drop a Variable Setter."), find_keycode_name(KEY_META)));#else				const_cast<VisualScriptEditor *>(this)->_show_hint(TTR("Hold Ctrl to drop a Variable Setter."));#endif			}			return true;		}	}	return false;}static Node *_find_script_node(Node *p_edited_scene, Node *p_current_node, const Ref<Script> &script) {	if (p_edited_scene != p_current_node && p_current_node->get_owner() != p_edited_scene) {		return nullptr;	}	Ref<Script> scr = p_current_node->get_script();	if (scr.is_valid() && scr == script) {		return p_current_node;	}	for (int i = 0; i < p_current_node->get_child_count(); i++) {		Node *n = _find_script_node(p_edited_scene, p_current_node->get_child(i), script);		if (n) {			return n;		}	}	return nullptr;}void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {	if (p_from != graph) {		return;	}	Dictionary d = p_data;	if (!d.has("type")) {		return;	}	if (String(d["type"]) == "visual_script_node_drag") {		if (!d.has("node_type") || String(d["node_type"]) == "Null") {			return;		}		Vector2 pos = _get_pos_in_graph(p_point);		int new_id = _create_new_node_from_name(d["node_type"], pos);		Node *node = graph->get_node(itos(new_id));		if (node) {			graph->set_selected(node);			_node_selected(node);		}	}	if (String(d["type"]) == "visual_script_variable_drag") {#ifdef OSX_ENABLED		bool use_set = Input::get_singleton()->is_key_pressed(KEY_META);#else		bool use_set = Input::get_singleton()->is_key_pressed(KEY_CTRL);#endif		Vector2 pos = _get_pos_in_graph(p_point);		Ref<VisualScriptNode> vnode;		if (use_set) {			Ref<VisualScriptVariableSet> vnodes;			vnodes.instantiate();			vnodes->set_variable(d["variable"]);			vnode = vnodes;		} else {			Ref<VisualScriptVariableGet> vnodeg;			vnodeg.instantiate();			vnodeg->set_variable(d["variable"]);			vnode = vnodeg;		}		int new_id = script->get_available_id();		undo_redo->create_action(TTR("Add Node"));		undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);		undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->commit_action();		Node *node = graph->get_node(itos(new_id));		if (node) {			graph->set_selected(node);			_node_selected(node);		}	}	if (String(d["type"]) == "visual_script_function_drag") {		Vector2 pos = _get_pos_in_graph(p_point);		Ref<VisualScriptFunctionCall> vnode;		vnode.instantiate();		vnode->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF);		int new_id = script->get_available_id();		undo_redo->create_action(TTR("Add Node"));		undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);		undo_redo->add_do_method(vnode.ptr(), "set_base_type", script->get_instance_base_type());		undo_redo->add_do_method(vnode.ptr(), "set_function", d["function"]);		undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->commit_action();		Node *node = graph->get_node(itos(new_id));		if (node) {			graph->set_selected(node);			_node_selected(node);		}	}	if (String(d["type"]) == "visual_script_signal_drag") {		Vector2 pos = _get_pos_in_graph(p_point);		Ref<VisualScriptEmitSignal> vnode;		vnode.instantiate();		vnode->set_signal(d["signal"]);		int new_id = script->get_available_id();		undo_redo->create_action(TTR("Add Node"));		undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);		undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->commit_action();		Node *node = graph->get_node(itos(new_id));		if (node) {			graph->set_selected(node);			_node_selected(node);		}	}	if (String(d["type"]) == "resource") {		Vector2 pos = _get_pos_in_graph(p_point);		Ref<VisualScriptPreload> prnode;		prnode.instantiate();		prnode->set_preload(d["resource"]);		int new_id = script->get_available_id();		undo_redo->create_action(TTR("Add Preload Node"));		undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos);		undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->commit_action();		Node *node = graph->get_node(itos(new_id));		if (node) {			graph->set_selected(node);			_node_selected(node);		}	}	if (String(d["type"]) == "files") {#ifdef OSX_ENABLED		bool use_preload = Input::get_singleton()->is_key_pressed(KEY_META);#else		bool use_preload = Input::get_singleton()->is_key_pressed(KEY_CTRL);#endif		Vector2 pos = _get_pos_in_graph(p_point);		Array files = d["files"];		List<int> new_ids;		int new_id = script->get_available_id();		if (files.size()) {			undo_redo->create_action(TTR("Add Node(s)"));			for (int i = 0; i < files.size(); i++) {				Ref<Resource> res = ResourceLoader::load(files[i]);				if (!res.is_valid()) {					continue;				}				Ref<Script> drop_script = ResourceLoader::load(files[i]);				if (drop_script.is_valid() && drop_script->is_tool() && drop_script->get_instance_base_type() == "VisualScriptCustomNode" && !use_preload) {					Ref<VisualScriptCustomNode> vscn;					vscn.instantiate();					vscn->set_script(drop_script);					undo_redo->add_do_method(script.ptr(), "add_node", new_id, vscn, pos);					undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);				} else {					Ref<VisualScriptPreload> prnode;					prnode.instantiate();					prnode->set_preload(res);					undo_redo->add_do_method(script.ptr(), "add_node", new_id, prnode, pos);					undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);				}				new_ids.push_back(new_id);				new_id++;				pos += Vector2(20, 20);			}			undo_redo->add_do_method(this, "_update_graph");			undo_redo->add_undo_method(this, "_update_graph");			undo_redo->commit_action();		}		for (int &E : new_ids) {			Node *node = graph->get_node(itos(E));			if (node) {				graph->set_selected(node);				_node_selected(node);			}		}	}	if (String(d["type"]) == "nodes") {		Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);		if (!sn) {			EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop nodes because script '%s' is not used in this scene."), get_name()));			return;		}#ifdef OSX_ENABLED		bool use_node = Input::get_singleton()->is_key_pressed(KEY_META);#else		bool use_node = Input::get_singleton()->is_key_pressed(KEY_CTRL);#endif		Array nodes = d["nodes"];		Vector2 pos = _get_pos_in_graph(p_point);		undo_redo->create_action(TTR("Add Node(s) From Tree"));		int base_id = script->get_available_id();		if (use_node || nodes.size() > 1) {			for (int i = 0; i < nodes.size(); i++) {				NodePath np = nodes[i];				Node *node = get_node(np);				if (!node) {					continue;				}				Ref<VisualScriptNode> n;				Ref<VisualScriptSceneNode> scene_node;				scene_node.instantiate();				scene_node->set_node_path(sn->get_path_to(node));				n = scene_node;				undo_redo->add_do_method(script.ptr(), "add_node", base_id, n, pos);				undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);				base_id++;				pos += Vector2(25, 25);			}		} else {			NodePath np = nodes[0];			Node *node = get_node(np);			drop_position = pos;			drop_node = node;			drop_path = sn->get_path_to(node);			new_connect_node_select->select_from_instance(node, "", false, node->get_class());		}		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->commit_action();	}	if (String(d["type"]) == "obj_property") {		Node *sn = _find_script_node(get_tree()->get_edited_scene_root(), get_tree()->get_edited_scene_root(), script);		if (!sn && !Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {			EditorNode::get_singleton()->show_warning(vformat(TTR("Can't drop properties because script '%s' is not used in this scene.\nDrop holding 'Shift' to just copy the signature."), get_name()));			return;		}		Object *obj = d["object"];		if (!obj) {			return;		}		Node *node = Object::cast_to<Node>(obj);		Vector2 pos = _get_pos_in_graph(p_point);#ifdef OSX_ENABLED		bool use_get = Input::get_singleton()->is_key_pressed(KEY_META);#else		bool use_get = Input::get_singleton()->is_key_pressed(KEY_CTRL);#endif		if (!node || Input::get_singleton()->is_key_pressed(KEY_SHIFT)) {			if (use_get) {				undo_redo->create_action(TTR("Add Getter Property"));			} else {				undo_redo->create_action(TTR("Add Setter Property"));			}			int base_id = script->get_available_id();			Ref<VisualScriptNode> vnode;			if (!use_get) {				Ref<VisualScriptPropertySet> pset;				pset.instantiate();				pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);				pset->set_base_type(obj->get_class());				/*if (use_value) {						pset->set_use_builtin_value(true);						pset->set_builtin_value(d["value"]);					}*/				vnode = pset;			} else {				Ref<VisualScriptPropertyGet> pget;				pget.instantiate();				pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);				pget->set_base_type(obj->get_class());				vnode = pget;			}			undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos);			undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);			if (!use_get) {				undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);			}			undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);			undo_redo->add_do_method(this, "_update_graph");			undo_redo->add_undo_method(this, "_update_graph");			undo_redo->commit_action();		} else {			if (use_get) {				undo_redo->create_action(TTR("Add Getter Property"));			} else {				undo_redo->create_action(TTR("Add Setter Property"));			}			int base_id = script->get_available_id();			Ref<VisualScriptNode> vnode;			if (!use_get) {				Ref<VisualScriptPropertySet> pset;				pset.instantiate();				if (sn == node) {					pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);				} else {					pset->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);					pset->set_base_path(sn->get_path_to(node));				}				vnode = pset;			} else {				Ref<VisualScriptPropertyGet> pget;				pget.instantiate();				if (sn == node) {					pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);				} else {					pget->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);					pget->set_base_path(sn->get_path_to(node));				}				vnode = pget;			}			undo_redo->add_do_method(script.ptr(), "add_node", base_id, vnode, pos);			undo_redo->add_do_method(vnode.ptr(), "set_property", d["property"]);			if (!use_get) {				undo_redo->add_do_method(vnode.ptr(), "set_default_input_value", 0, d["value"]);			}			undo_redo->add_undo_method(script.ptr(), "remove_node", base_id);			undo_redo->add_do_method(this, "_update_graph");			undo_redo->add_undo_method(this, "_update_graph");			undo_redo->commit_action();		}	}}void VisualScriptEditor::_draw_color_over_button(Object *obj, Color p_color) {	Button *button = Object::cast_to<Button>(obj);	if (!button) {		return;	}	Ref<StyleBox> normal = get_theme_stylebox(SNAME("normal"), SNAME("Button"));	button->draw_rect(Rect2(normal->get_offset(), button->get_size() - normal->get_minimum_size()), p_color);}void VisualScriptEditor::_button_resource_previewed(const String &p_path, const Ref<Texture2D> &p_preview, const Ref<Texture2D> &p_small_preview, Variant p_ud) {	Array ud = p_ud;	ERR_FAIL_COND(ud.size() != 2);	ObjectID id = ud[0];	Object *obj = ObjectDB::get_instance(id);	if (!obj) {		return;	}	Button *b = Object::cast_to<Button>(obj);	ERR_FAIL_COND(!b);	if (p_preview.is_null()) {		b->set_text(ud[1]);	} else {		b->set_icon(p_preview);	}}/////////////////////////void VisualScriptEditor::apply_code() {}RES VisualScriptEditor::get_edited_resource() const {	return script;}void VisualScriptEditor::set_edited_resource(const RES &p_res) {	ERR_FAIL_COND(script.is_valid());	ERR_FAIL_COND(p_res.is_null());	script = p_res;	signal_editor->script = script;	signal_editor->undo_redo = undo_redo;	variable_editor->script = script;	variable_editor->undo_redo = undo_redo;	script->connect("node_ports_changed", callable_mp(this, &VisualScriptEditor::_node_ports_changed));	_update_graph();	call_deferred(SNAME("_update_members"));}void VisualScriptEditor::enable_editor() {}Vector<String> VisualScriptEditor::get_functions() {	return Vector<String>();}void VisualScriptEditor::reload_text() {}String VisualScriptEditor::get_name() {	String name;	if (script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) {		name = script->get_path().get_file();		if (is_unsaved()) {			if (script->get_path().is_empty()) {				name = TTR("[unsaved]");			}			name += "(*)";		}	} else if (script->get_name() != "") {		name = script->get_name();	} else {		name = script->get_class() + "(" + itos(script->get_instance_id()) + ")";	}	return name;}Ref<Texture2D> VisualScriptEditor::get_theme_icon() {	return Control::get_theme_icon(SNAME("VisualScript"), SNAME("EditorIcons"));}bool VisualScriptEditor::is_unsaved() {	bool unsaved =			script->is_edited() ||			script->are_subnodes_edited() ||			script->get_path().is_empty(); // In memory.	return unsaved;}Variant VisualScriptEditor::get_edit_state() {	Dictionary d;	d["scroll"] = graph->get_scroll_ofs();	d["zoom"] = graph->get_zoom();	d["using_snap"] = graph->is_using_snap();	d["snap"] = graph->get_snap();	return d;}void VisualScriptEditor::set_edit_state(const Variant &p_state) {	Dictionary d = p_state;	_update_graph();	_update_members();	if (d.has("scroll")) {		graph->set_scroll_ofs(d["scroll"]);	}	if (d.has("zoom")) {		graph->set_zoom(d["zoom"]);	}	if (d.has("snap")) {		graph->set_snap(d["snap"]);	}	if (d.has("snap_enabled")) {		graph->set_use_snap(d["snap_enabled"]);	}}void VisualScriptEditor::_center_on_node(int p_id) {	Node *n = graph->get_node(itos(p_id));	GraphNode *gn = Object::cast_to<GraphNode>(n);	// Clear selection.	for (int i = 0; i < graph->get_child_count(); i++) {		GraphNode *gnd = Object::cast_to<GraphNode>(graph->get_child(i));		if (gnd) {			gnd->set_selected(false);		}	}	if (gn) {		gn->set_selected(true);		Vector2 new_scroll = gn->get_position_offset() - graph->get_size() * 0.5 + gn->get_size() * 0.5;		graph->set_scroll_ofs(new_scroll);		script->set_scroll(new_scroll / EDSCALE);		script->set_edited(true);	}}void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {	p_line += 1; // Add one because script lines begin from 0.	if (p_with_error) {		error_line = p_line;	}	List<StringName> functions;	script->get_function_list(&functions);	for (const StringName &E : functions) {		if (script->has_node(p_line)) {			_update_graph();			_update_members();			call_deferred(SNAME("call_deferred"), "_center_on_node", E, p_line); //editor might be just created and size might not exist yet			return;		}	}}void VisualScriptEditor::set_executing_line(int p_line) {	// todo: add a way to show which node is executing right now.}void VisualScriptEditor::clear_executing_line() {	// todo: add a way to show which node is executing right now.}void VisualScriptEditor::trim_trailing_whitespace() {}void VisualScriptEditor::insert_final_newline() {}void VisualScriptEditor::convert_indent_to_spaces() {}void VisualScriptEditor::convert_indent_to_tabs() {}void VisualScriptEditor::ensure_focus() {	graph->grab_focus();}void VisualScriptEditor::tag_saved_version() {}void VisualScriptEditor::reload(bool p_soft) {	_update_graph();}Array VisualScriptEditor::get_breakpoints() {	Array breakpoints;	List<StringName> functions;	script->get_function_list(&functions);	for (int i = 0; i < functions.size(); i++) {		List<int> nodes;		script->get_node_list(&nodes);		for (int &F : nodes) {			Ref<VisualScriptNode> vsn = script->get_node(F);			if (vsn->is_breakpoint()) {				breakpoints.push_back(F - 1); // Subtract 1 because breakpoints in text start from zero.			}		}	}	return breakpoints;}void VisualScriptEditor::add_callback(const String &p_function, PackedStringArray p_args) {	if (script->has_function(p_function)) {		_update_members();		_update_graph();		_center_on_node(script->get_function_node_id(p_function));		return;	}	Ref<VisualScriptFunction> func;	func.instantiate();	for (int i = 0; i < p_args.size(); i++) {		String name = p_args[i];		Variant::Type type = Variant::NIL;		if (name.find(":") != -1) {			String tt = name.get_slice(":", 1);			name = name.get_slice(":", 0);			for (int j = 0; j < Variant::VARIANT_MAX; j++) {				String tname = Variant::get_type_name(Variant::Type(j));				if (tname == tt) {					type = Variant::Type(j);					break;				}			}		}		func->add_argument(type, name);	}	int fn_id = script->get_available_id();	func->set_name(p_function);	script->add_function(p_function, fn_id);	script->add_node(fn_id, func);	_update_members();	_update_graph();	_center_on_node(script->get_function_node_id(p_function));}bool VisualScriptEditor::show_members_overview() {	return false;}void VisualScriptEditor::update_settings() {	_update_graph();}void VisualScriptEditor::set_debugger_active(bool p_active) {	if (!p_active) {		error_line = -1;		_update_graph(); //clear line break	}}Control *VisualScriptEditor::get_base_editor() const {	return graph;}void VisualScriptEditor::set_tooltip_request_func(String p_method, Object *p_obj) {}Control *VisualScriptEditor::get_edit_menu() {	return edit_menu;}void VisualScriptEditor::_change_base_type() {	select_base_type->popup_create(true, true);}void VisualScriptEditor::_toggle_tool_script() {	script->set_tool_enabled(!script->is_tool());}void VisualScriptEditor::clear_edit_menu() {	memdelete(edit_menu);	memdelete(members_section);}void VisualScriptEditor::_change_base_type_callback() {	String bt = select_base_type->get_selected_type();	ERR_FAIL_COND(bt == String());	undo_redo->create_action(TTR("Change Base Type"));	undo_redo->add_do_method(script.ptr(), "set_instance_base_type", bt);	undo_redo->add_undo_method(script.ptr(), "set_instance_base_type", script->get_instance_base_type());	undo_redo->add_do_method(this, "_update_members");	undo_redo->add_undo_method(this, "_update_members");	undo_redo->commit_action();}void VisualScriptEditor::_node_selected(Node *p_node) {	Ref<VisualScriptNode> vnode = p_node->get_meta("__vnode");	if (vnode.is_null()) {		return;	}	EditorNode::get_singleton()->push_item(vnode.ptr()); //edit node in inspector}static bool _get_out_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) {	if (p_slot < p_node->get_output_sequence_port_count()) {		r_sequence = true;		r_real_slot = p_slot;		return true;	}	r_real_slot = p_slot - p_node->get_output_sequence_port_count();	r_sequence = false;	return (r_real_slot < p_node->get_output_value_port_count());}static bool _get_in_slot(const Ref<VisualScriptNode> &p_node, int p_slot, int &r_real_slot, bool &r_sequence) {	if (p_slot == 0 && p_node->has_input_sequence_port()) {		r_sequence = true;		r_real_slot = 0;		return true;	}	r_real_slot = p_slot - (p_node->has_input_sequence_port() ? 1 : 0);	r_sequence = false;	return r_real_slot < p_node->get_input_value_port_count();}void VisualScriptEditor::_begin_node_move() {	undo_redo->create_action(TTR("Move Node(s)"));}void VisualScriptEditor::_end_node_move() {	undo_redo->commit_action();}void VisualScriptEditor::_move_node(int p_id, const Vector2 &p_to) {	if (!script->has_node(p_id)) {		return;	}	Node *node = graph->get_node(itos(p_id));	if (Object::cast_to<GraphNode>(node)) {		Object::cast_to<GraphNode>(node)->set_position_offset(p_to);	}	script->set_node_position(p_id, p_to / EDSCALE);}void VisualScriptEditor::_node_moved(Vector2 p_from, Vector2 p_to, int p_id) {	undo_redo->add_do_method(this, "_move_node", p_id, p_to);	undo_redo->add_undo_method(this, "_move_node", p_id, p_from);}void VisualScriptEditor::_remove_node(int p_id) {	undo_redo->create_action(TTR("Remove VisualScript Node"));	undo_redo->add_do_method(script.ptr(), "remove_node", p_id);	undo_redo->add_undo_method(script.ptr(), "add_node", p_id, script->get_node(p_id), script->get_node_position(p_id));	List<VisualScript::SequenceConnection> sequence_conns;	script->get_sequence_connection_list(&sequence_conns);	for (const VisualScript::SequenceConnection &E : sequence_conns) {		if (E.from_node == p_id || E.to_node == p_id) {			undo_redo->add_undo_method(script.ptr(), "sequence_connect", E.from_node, E.from_output, E.to_node);		}	}	List<VisualScript::DataConnection> data_conns;	script->get_data_connection_list(&data_conns);	for (const VisualScript::DataConnection &E : data_conns) {		if (E.from_node == p_id || E.to_node == p_id) {			undo_redo->add_undo_method(script.ptr(), "data_connect", E.from_node, E.from_port, E.to_node, E.to_port);		}	}	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->commit_action();}void VisualScriptEditor::_node_ports_changed(int p_id) {	_update_graph(p_id);}bool VisualScriptEditor::node_has_sequence_connections(int p_id) {	List<VisualScript::SequenceConnection> sequence_conns;	script->get_sequence_connection_list(&sequence_conns);	for (const VisualScript::SequenceConnection &E : sequence_conns) {		int from = E.from_node;		int to = E.to_node;		if (to == p_id || from == p_id) {			return true;		}	}	return false;}void VisualScriptEditor::_graph_connected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {	Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int());	ERR_FAIL_COND(!from_node.is_valid());	bool from_seq;	int from_port;	if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) {		return; //can't connect this, it's invalid	}	Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int());	ERR_FAIL_COND(!to_node.is_valid());	bool to_seq;	int to_port;	if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) {		return; //can't connect this, it's invalid	}	ERR_FAIL_COND(from_seq != to_seq);	// Checking to prevent warnings.	if (from_seq) {		if (script->has_sequence_connection(p_from.to_int(), from_port, p_to.to_int())) {			return;		}	} else if (script->has_data_connection(p_from.to_int(), from_port, p_to.to_int(), to_port)) {		return;	}	// Preventing connection to itself.	if (p_from.to_int() == p_to.to_int()) {		return;	}	// Do all the checks here.	StringName func; // This the func where we store the one the nodes at the end of the resolution on having multiple nodes.	undo_redo->create_action(TTR("Connect Nodes"));	if (from_seq) {		undo_redo->add_do_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int());		// This undo error on undo after move can't be removed without painful gymnastics		undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int());		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");	} else {		bool converted = false;		Ref<VisualScriptOperator> oper = to_node;		if (oper.is_valid() && oper->get_typed() == Variant::NIL) {			// It's an operator Node and if the type is already nil			if (from_node->get_output_value_port_info(from_port).type != Variant::NIL) {				oper->set_typed(from_node->get_output_value_port_info(from_port).type);			}		}		Ref<VisualScriptOperator> operf = from_node;		if (operf.is_valid() && operf->get_typed() == Variant::NIL) {			// It's an operator Node and if the type is already nil			if (to_node->get_input_value_port_info(to_port).type != Variant::NIL) {				operf->set_typed(to_node->get_input_value_port_info(to_port).type);			}		}		// Disconnect current, and connect the new one		if (script->is_input_value_port_connected(p_to.to_int(), to_port)) {			if (can_swap && data_disconnect_node == p_to.to_int()) {				int conn_from;				int conn_port;				script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port);				undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port);				undo_redo->add_do_method(script.ptr(), "data_connect", conn_from, conn_port, data_disconnect_node, data_disconnect_port);				undo_redo->add_undo_method(script.ptr(), "data_disconnect", conn_from, conn_port, data_disconnect_node, data_disconnect_port);				undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port);				can_swap = false; // swapped			} else {				int conn_from;				int conn_port;				script->get_input_value_port_connection_source(p_to.to_int(), to_port, &conn_from, &conn_port);				undo_redo->add_do_method(script.ptr(), "data_disconnect", conn_from, conn_port, p_to.to_int(), to_port);				undo_redo->add_undo_method(script.ptr(), "data_connect", conn_from, conn_port, p_to.to_int(), to_port);			}		}		if (!converted) {			undo_redo->add_do_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);			undo_redo->add_undo_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);		}		// Update nodes in graph		if (!converted) {			undo_redo->add_do_method(this, "_update_graph", p_from.to_int());			undo_redo->add_do_method(this, "_update_graph", p_to.to_int());			undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());			undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());		} else {			undo_redo->add_do_method(this, "_update_graph");			undo_redo->add_undo_method(this, "_update_graph");		}	}	undo_redo->commit_action();}void VisualScriptEditor::_graph_disconnected(const String &p_from, int p_from_slot, const String &p_to, int p_to_slot) {	Ref<VisualScriptNode> from_node = script->get_node(p_from.to_int());	ERR_FAIL_COND(!from_node.is_valid());	bool from_seq;	int from_port;	if (!_get_out_slot(from_node, p_from_slot, from_port, from_seq)) {		return; // Can't connect this, it's invalid.	}	Ref<VisualScriptNode> to_node = script->get_node(p_to.to_int());	ERR_FAIL_COND(!to_node.is_valid());	bool to_seq;	int to_port;	if (!_get_in_slot(to_node, p_to_slot, to_port, to_seq)) {		return; // Can't connect this, it's invalid.	}	ERR_FAIL_COND(from_seq != to_seq);	undo_redo->create_action(TTR("Disconnect Nodes"));	if (from_seq) {		undo_redo->add_do_method(script.ptr(), "sequence_disconnect", p_from.to_int(), from_port, p_to.to_int());		undo_redo->add_undo_method(script.ptr(), "sequence_connect", p_from.to_int(), from_port, p_to.to_int());		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");	} else {		can_swap = true;		data_disconnect_node = p_to.to_int();		data_disconnect_port = to_port;		undo_redo->add_do_method(script.ptr(), "data_disconnect", p_from.to_int(), from_port, p_to.to_int(), to_port);		undo_redo->add_undo_method(script.ptr(), "data_connect", p_from.to_int(), from_port, p_to.to_int(), to_port);		// Update relevant nodes in the graph.		undo_redo->add_do_method(this, "_update_graph", p_from.to_int());		undo_redo->add_do_method(this, "_update_graph", p_to.to_int());		undo_redo->add_undo_method(this, "_update_graph", p_from.to_int());		undo_redo->add_undo_method(this, "_update_graph", p_to.to_int());	}	undo_redo->commit_action();}void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_from_slot, const Vector2 &p_release_pos) {	Node *node = graph->get_node(p_from);	GraphNode *gn = Object::cast_to<GraphNode>(node);	if (!gn) {		return;	}	Ref<VisualScriptNode> vsn = script->get_node(p_from.to_int());	if (!vsn.is_valid()) {		return;	}	if (vsn->get_output_value_port_count() || vsn->get_output_sequence_port_count()) {		port_action_pos = p_release_pos;	}	if (p_from_slot < vsn->get_output_sequence_port_count()) {		port_action_node = p_from.to_int();		port_action_output = p_from_slot;		_port_action_menu(CREATE_ACTION);	} else {		port_action_output = p_from_slot - vsn->get_output_sequence_port_count();		port_action_node = p_from.to_int();		_port_action_menu(CREATE_CALL_SET_GET);	}}VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes) {	VisualScriptNode::TypeGuess tg;	tg.type = Variant::NIL;	if (visited_nodes.has(p_port_action_node)) {		return tg; //no loop	}	visited_nodes.insert(p_port_action_node);	Ref<VisualScriptNode> node = script->get_node(p_port_action_node);	if (!node.is_valid() || node->get_output_value_port_count() <= p_port_action_output) {		return tg;	}	Vector<VisualScriptNode::TypeGuess> in_guesses;	for (int i = 0; i < node->get_input_value_port_count(); i++) {		PropertyInfo pi = node->get_input_value_port_info(i);		VisualScriptNode::TypeGuess g;		g.type = pi.type;		if (g.type == Variant::NIL || g.type == Variant::OBJECT) {			// Any or object input, must further guess what this is.			int from_node;			int from_port;			if (script->get_input_value_port_connection_source(p_port_action_node, i, &from_node, &from_port)) {				g = _guess_output_type(from_node, from_port, visited_nodes);			} else {				Variant defval = node->get_default_input_value(i);				if (defval.get_type() == Variant::OBJECT) {					Object *obj = defval;					if (obj) {						g.type = Variant::OBJECT;						g.gdclass = obj->get_class();						g.script = obj->get_script();					}				}			}		}		in_guesses.push_back(g);	}	return node->guess_output_type(in_guesses.ptrw(), p_port_action_output);}void VisualScriptEditor::_port_action_menu(int p_option) {	Set<int> vn;	switch (p_option) {		case CREATE_CALL_SET_GET: {			Ref<VisualScriptFunctionCall> n;			n.instantiate();			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);			if (tg.gdclass != StringName()) {				n->set_base_type(tg.gdclass);			} else {				n->set_base_type("Object");			}			String type_string;			if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {				type_string = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;			}			if (tg.type == Variant::OBJECT) {				if (tg.script.is_valid()) {					new_connect_node_select->select_from_script(tg.script, "");				} else if (type_string != String()) {					new_connect_node_select->select_from_base_type(type_string);				} else {					new_connect_node_select->select_from_base_type(n->get_base_type());				}			} else if (tg.type == Variant::NIL) {				new_connect_node_select->select_from_base_type("");			} else {				new_connect_node_select->select_from_basic_type(tg.type);			}			// Ensure that the dialog fits inside the graph.			Vector2 pos = mouse_up_position;			Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();			pos.x = pos.x > bounds.x ? bounds.x : pos.x;			pos.y = pos.y > bounds.y ? bounds.y : pos.y;			new_connect_node_select->set_position(pos);		} break;		case CREATE_ACTION: {			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);			PropertyInfo property_info;			if (script->get_node(port_action_node)->get_output_value_port_count() > 0) {				property_info = script->get_node(port_action_node)->get_output_value_port_info(port_action_output);			}			if (tg.type == Variant::OBJECT) {				if (property_info.type == Variant::OBJECT && property_info.hint_string != String()) {					new_connect_node_select->select_from_action(property_info.hint_string);				} else {					new_connect_node_select->select_from_action("");				}			} else if (tg.type == Variant::NIL) {				new_connect_node_select->select_from_action("");			} else {				new_connect_node_select->select_from_action(Variant::get_type_name(tg.type));			}			// Ensure that the dialog fits inside the graph.			Vector2 pos = mouse_up_position;			Size2 bounds = graph->get_global_position() + graph->get_size() - new_connect_node_select->get_size();			pos.x = pos.x > bounds.x ? bounds.x : pos.x;			pos.y = pos.y > bounds.y ? bounds.y : pos.y;			new_connect_node_select->set_position(pos);		} break;	}}void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id) {	undo_redo->create_action(TTR("Connect Node Data"));	VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr());	if (vnode_return != nullptr && vnode_old->get_output_value_port_count() > 0) {		vnode_return->set_enable_return_value(true);	}	if (vnode_old->get_output_value_port_count() <= 0) {		undo_redo->commit_action();		return;	}	if (vnode->get_input_value_port_count() <= 0) {		undo_redo->commit_action();		return;	}	int port = port_action_output;	int value_count = vnode_old->get_output_value_port_count();	if (port >= value_count) {		port = 0;	}	undo_redo->add_do_method(script.ptr(), "data_connect", port_action_node, port, new_id, 0);	undo_redo->add_undo_method(script.ptr(), "data_disconnect", port_action_node, port, new_id, 0);	undo_redo->commit_action();}void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category, const bool p_connecting) {	Vector2 pos = _get_pos_in_graph(port_action_pos);	Set<int> vn;	if (drop_position != Vector2()) {		pos = drop_position;	}	drop_position = Vector2();	bool port_node_exists = true;	// if (func == StringName()) {	// 	func = default_func;	// 	port_node_exists = false;	// }	if (p_category == "visualscript") {		Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text);		Ref<VisualScriptNode> vnode_old;		if (port_node_exists && p_connecting) {			vnode_old = script->get_node(port_action_node);		}		int new_id = script->get_available_id();		if (Object::cast_to<VisualScriptOperator>(vnode_new.ptr()) && vnode_old.is_valid()) {			Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;			Object::cast_to<VisualScriptOperator>(vnode_new.ptr())->set_typed(type);		}		if (Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr()) && vnode_old.is_valid()) {			Variant::Type type = vnode_old->get_output_value_port_info(port_action_output).type;			String hint_name = vnode_old->get_output_value_port_info(port_action_output).hint_string;			if (type == Variant::OBJECT) {				Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(hint_name);			} else if (type == Variant::NIL) {				Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type("");			} else {				Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(Variant::get_type_name(type));			}		}		undo_redo->create_action(TTR("Add Node"));		undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode_new, pos);		if (vnode_old.is_valid() && p_connecting) {			connect_seq(vnode_old, vnode_new, new_id);			connect_data(vnode_old, vnode_new, new_id);		}		undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);		undo_redo->add_do_method(this, "_update_graph");		undo_redo->add_undo_method(this, "_update_graph");		undo_redo->commit_action();		return;	}	Ref<VisualScriptNode> vnode;	Ref<VisualScriptPropertySet> script_prop_set;	if (p_category == String("method")) {		Ref<VisualScriptFunctionCall> n;		n.instantiate();		if (!drop_path.is_empty()) {			if (drop_path == ".") {				n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_SELF);			} else {				n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_NODE_PATH);				n->set_base_path(drop_path);			}		}		if (drop_node) {			n->set_base_type(drop_node->get_class());			if (drop_node->get_script_instance()) {				n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());			}		}		vnode = n;	} else if (p_category == String("set")) {		Ref<VisualScriptPropertySet> n;		n.instantiate();		if (!drop_path.is_empty()) {			if (drop_path == ".") {				n->set_call_mode(VisualScriptPropertySet::CALL_MODE_SELF);			} else {				n->set_call_mode(VisualScriptPropertySet::CALL_MODE_NODE_PATH);				n->set_base_path(drop_path);			}		}		if (drop_node) {			n->set_base_type(drop_node->get_class());			if (drop_node->get_script_instance()) {				n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());			}		}		vnode = n;		script_prop_set = n;	} else if (p_category == String("get")) {		Ref<VisualScriptPropertyGet> n;		n.instantiate();		n->set_property(p_text);		if (!drop_path.is_empty()) {			if (drop_path == ".") {				n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_SELF);			} else {				n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_NODE_PATH);				n->set_base_path(drop_path);			}		}		if (drop_node) {			n->set_base_type(drop_node->get_class());			if (drop_node->get_script_instance()) {				n->set_base_script(drop_node->get_script_instance()->get_script()->get_path());			}		}		vnode = n;	}	drop_path = String();	drop_node = nullptr;	if (p_category == String("action")) {		if (p_text == "VisualScriptCondition") {			Ref<VisualScriptCondition> n;			n.instantiate();			vnode = n;		}		if (p_text == "VisualScriptSwitch") {			Ref<VisualScriptSwitch> n;			n.instantiate();			vnode = n;		} else if (p_text == "VisualScriptSequence") {			Ref<VisualScriptSequence> n;			n.instantiate();			vnode = n;		} else if (p_text == "VisualScriptIterator") {			Ref<VisualScriptIterator> n;			n.instantiate();			vnode = n;		} else if (p_text == "VisualScriptWhile") {			Ref<VisualScriptWhile> n;			n.instantiate();			vnode = n;		} else if (p_text == "VisualScriptReturn") {			Ref<VisualScriptReturn> n;			n.instantiate();			vnode = n;		}	}	int new_id = script->get_available_id();	undo_redo->create_action(TTR("Add Node"));	undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, pos);	undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);	undo_redo->add_do_method(this, "_update_graph", new_id);	undo_redo->add_undo_method(this, "_update_graph", new_id);	undo_redo->commit_action();	if (script_prop_set.is_valid()) {		script_prop_set->set_property(p_text);	}	port_action_new_node = new_id;	Ref<VisualScriptNode> vsn = script->get_node(port_action_new_node);	if (Object::cast_to<VisualScriptFunctionCall>(vsn.ptr())) {		Ref<VisualScriptFunctionCall> vsfc = vsn;		vsfc->set_function(p_text);		if (port_node_exists && p_connecting) {			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);			if (tg.type == Variant::OBJECT) {				vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);				vsfc->set_base_type(String(""));				if (tg.gdclass != StringName()) {					vsfc->set_base_type(tg.gdclass);				} else if (script->get_node(port_action_node).is_valid()) {					PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;					String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;					if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {						vsfc->set_base_type(base_type);					}					if (p_text == "call" || p_text == "call_deferred") {						vsfc->set_function(String(""));					}				}				if (tg.script.is_valid()) {					vsfc->set_base_script(tg.script->get_path());				}			} else if (tg.type == Variant::NIL) {				vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);				vsfc->set_base_type(String(""));			} else {				vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);				vsfc->set_basic_type(tg.type);			}		}	}	if (port_node_exists && p_connecting) {		if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) {			Ref<VisualScriptPropertySet> vsp = vsn;			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);			if (tg.type == Variant::OBJECT) {				vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);				vsp->set_base_type(String(""));				if (tg.gdclass != StringName()) {					vsp->set_base_type(tg.gdclass);				} else if (script->get_node(port_action_node).is_valid()) {					PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;					String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;					if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {						vsp->set_base_type(base_type);					}				}				if (tg.script.is_valid()) {					vsp->set_base_script(tg.script->get_path());				}			} else if (tg.type == Variant::NIL) {				vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);				vsp->set_base_type(String(""));			} else {				vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE);				vsp->set_basic_type(tg.type);			}		}		if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) {			Ref<VisualScriptPropertyGet> vsp = vsn;			VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);			if (tg.type == Variant::OBJECT) {				vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);				vsp->set_base_type(String(""));				if (tg.gdclass != StringName()) {					vsp->set_base_type(tg.gdclass);				} else if (script->get_node(port_action_node).is_valid()) {					PropertyHint hint = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint;					String base_type = script->get_node(port_action_node)->get_output_value_port_info(port_action_output).hint_string;					if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {						vsp->set_base_type(base_type);					}				}				if (tg.script.is_valid()) {					vsp->set_base_script(tg.script->get_path());				}			} else if (tg.type == Variant::NIL) {				vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);				vsp->set_base_type(String(""));			} else {				vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE);				vsp->set_basic_type(tg.type);			}		}	}	if (port_node_exists) {		Ref<VisualScriptNode> vnode_old = script->get_node(port_action_node);		if (vnode_old.is_valid() && p_connecting) {			connect_seq(vnode_old, vnode, port_action_new_node);			connect_data(vnode_old, vnode, port_action_new_node);		}	}	_update_graph(port_action_new_node);}void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) {	VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr());	if (vnode_operator != nullptr && !vnode_operator->has_input_sequence_port()) {		return;	}	VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr());	if (vnode_constructor != nullptr) {		return;	}	if (vnode_old->get_output_sequence_port_count() <= 0) {		return;	}	if (!vnode_new->has_input_sequence_port()) {		return;	}	undo_redo->create_action(TTR("Connect Node Sequence"));	int pass_port = -vnode_old->get_output_sequence_port_count() + 1;	int return_port = port_action_output - 1;	if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") &&			!script->get_output_sequence_ports_connected(port_action_node).has(pass_port)) {		undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, pass_port, new_id);		undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, pass_port, new_id);	} else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") &&			   !script->get_output_sequence_ports_connected(port_action_node).has(return_port)) {		undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, return_port, new_id);		undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, return_port, new_id);	} else {		for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) {			int count = vnode_old->get_output_sequence_port_count();			if (port_action_output < count && !script->get_output_sequence_ports_connected(port_action_node).has(port_action_output)) {				undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port_action_output, new_id);				undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port_action_output, new_id);				break;			} else if (!script->get_output_sequence_ports_connected(port_action_node).has(port)) {				undo_redo->add_do_method(script.ptr(), "sequence_connect", port_action_node, port, new_id);				undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", port_action_node, port, new_id);				break;			}		}	}	undo_redo->commit_action();}void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category, const bool p_connecting) {	String name = p_text;	if (script->has_function(name)) {		EditorNode::get_singleton()->show_warning(vformat(TTR("Script already has function '%s'"), name));		return;	}	MethodInfo minfo;	{		List<MethodInfo> methods;		bool found = false;		ClassDB::get_virtual_methods(script->get_instance_base_type(), &methods);		for (const MethodInfo &E : methods) {			if (E.name == name) {				minfo = E;				found = true;			}		}		ERR_FAIL_COND(!found);	}	selected = name;	Ref<VisualScriptFunction> func_node;	func_node.instantiate();	func_node->set_name(name);	int fn_id = script->get_available_id();	undo_redo->create_action(TTR("Add Function"));	undo_redo->add_do_method(script.ptr(), "add_function", name, fn_id);	for (int i = 0; i < minfo.arguments.size(); i++) {		func_node->add_argument(minfo.arguments[i].type, minfo.arguments[i].name, -1, minfo.arguments[i].hint, minfo.arguments[i].hint_string);	}	Vector2 pos = _get_available_pos();	undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos);	undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);	if (minfo.return_val.type != Variant::NIL || minfo.return_val.usage & PROPERTY_USAGE_NIL_IS_VARIANT) {		Ref<VisualScriptReturn> ret_node;		ret_node.instantiate();		ret_node->set_return_type(minfo.return_val.type);		ret_node->set_enable_return_value(true);		ret_node->set_name(name);		int nid = script->get_available_id() + 1;		undo_redo->add_do_method(script.ptr(), "add_node", nid, ret_node, _get_available_pos(false, pos + Vector2(500, 0)));		undo_redo->add_undo_method(script.ptr(), "remove_node", nid);	}	undo_redo->add_undo_method(script.ptr(), "remove_function", name);	undo_redo->add_do_method(this, "_update_members");	undo_redo->add_undo_method(this, "_update_members");	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->commit_action();	_update_graph();}void VisualScriptEditor::_cancel_connect_node() {	// Ensure the cancel is done.	port_action_new_node = -1;}int VisualScriptEditor::_create_new_node_from_name(const String &p_text, const Vector2 &p_point) {	Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text);	int new_id = script->get_available_id();	undo_redo->create_action(TTR("Add Node"));	undo_redo->add_do_method(script.ptr(), "add_node", new_id, vnode, p_point);	undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);	undo_redo->add_do_method(this, "_update_graph");	undo_redo->add_undo_method(this, "_update_graph");	undo_redo->commit_action();	return new_id;}void VisualScriptEditor::_default_value_changed() {	Ref<VisualScriptNode> vsn = script->get_node(editing_id);	if (vsn.is_null()) {		return;	}	undo_redo->create_action(TTR("Change Input Value"));	undo_redo->add_do_method(vsn.ptr(), "set_default_input_value", editing_input, default_value_edit->get_variant());	undo_redo->add_undo_method(vsn.ptr(), "set_default_input_value", editing_input, vsn->get_default_input_value(editing_input));	undo_redo->add_do_method(this, "_update_graph", editing_id);	undo_redo->add_undo_method(this, "_update_graph", editing_id);	undo_redo->commit_action();}void VisualScriptEditor::_default_value_edited(Node *p_button, int p_id, int p_input_port) {	Ref<VisualScriptNode> vsn = script->get_node(p_id);	if (vsn.is_null()) {		return;	}	PropertyInfo pinfo = vsn->get_input_value_port_info(p_input_port);	Variant existing = vsn->get_default_input_value(p_input_port);	if (pinfo.type != Variant::NIL && existing.get_type() != pinfo.type) {		Callable::CallError ce;		Variant e = existing;		const Variant *existingp = &e;		Variant::construct(pinfo.type, existing, &existingp, 1, ce);	}	default_value_edit->set_position(Object::cast_to<Control>(p_button)->get_global_position() + Vector2(0, Object::cast_to<Control>(p_button)->get_size().y));	default_value_edit->set_size(Size2(1, 1));	if (pinfo.type == Variant::NODE_PATH) {		Node *edited_scene = get_tree()->get_edited_scene_root();		if (edited_scene) { // Fixing an old crash bug ( Visual Script Crashes on editing NodePath with an empty scene open).			Node *script_node = _find_script_node(edited_scene, edited_scene, script);			if (script_node) {				// Pick a node relative to the script, IF the script exists.				pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;				pinfo.hint_string = script_node->get_path();			} else {				// Pick a path relative to edited scene.				pinfo.hint = PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE;				pinfo.hint_string = get_tree()->get_edited_scene_root()->get_path();			}		}	}	if (default_value_edit->edit(nullptr, pinfo.name, pinfo.type, existing, pinfo.hint, pinfo.hint_string)) {		if (pinfo.hint == PROPERTY_HINT_MULTILINE_TEXT) {			default_value_edit->popup_centered_ratio();		} else {			default_value_edit->popup();		}	}	editing_id = p_id;	editing_input = p_input_port;}void VisualScriptEditor::_show_hint(const String &p_hint) {	hint_text->set_text(p_hint);	hint_text->show();	hint_text_timer->start();}void VisualScriptEditor::_hide_timer() {	hint_text->hide();}void VisualScriptEditor::_notification(int p_what) {	switch (p_what) {		case NOTIFICATION_READY: {			variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));			variable_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED);			signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_members));			signal_editor->connect("changed", callable_mp(this, &VisualScriptEditor::_update_graph), varray(-1), CONNECT_DEFERRED);			[[fallthrough]];		}		case NOTIFICATION_THEME_CHANGED: {			if (p_what != NOTIFICATION_READY && !is_visible_in_tree()) {				return;			}			edit_variable_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));			edit_signal_edit->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));			func_input_scroll->add_theme_style_override("bg", get_theme_stylebox(SNAME("bg"), SNAME("Tree")));			Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();			bool dark_theme = tm->get_constant("dark_theme", "Editor");			if (dark_theme) {				node_colors["flow_control"] = Color(0.96, 0.96, 0.96);				node_colors["functions"] = Color(0.96, 0.52, 0.51);				node_colors["data"] = Color(0.5, 0.96, 0.81);				node_colors["operators"] = Color(0.67, 0.59, 0.87);				node_colors["custom"] = Color(0.5, 0.73, 0.96);				node_colors["constants"] = Color(0.96, 0.5, 0.69);			} else {				node_colors["flow_control"] = Color(0.26, 0.26, 0.26);				node_colors["functions"] = Color(0.95, 0.4, 0.38);				node_colors["data"] = Color(0.07, 0.73, 0.51);				node_colors["operators"] = Color(0.51, 0.4, 0.82);				node_colors["custom"] = Color(0.31, 0.63, 0.95);				node_colors["constants"] = Color(0.94, 0.18, 0.49);			}			for (Map<StringName, Color>::Element *E = node_colors.front(); E; E = E->next()) {				const Ref<StyleBoxFlat> sb = tm->get_stylebox(SNAME("frame"), SNAME("GraphNode"));				if (!sb.is_null()) {					Ref<StyleBoxFlat> frame_style = sb->duplicate();					// Adjust the border color to be close to the GraphNode's background color.					// This keeps the node's title area from being too distracting.					Color color = dark_theme ? E->get().darkened(0.75) : E->get().lightened(0.75);					color.a = 0.9;					frame_style->set_border_color(color);					node_styles[E->key()] = frame_style;				}			}			if (is_visible_in_tree() && script.is_valid()) {				_update_members();				_update_graph();			}		} break;		case NOTIFICATION_VISIBILITY_CHANGED: {			members_section->set_visible(is_visible_in_tree());		} break;	}}void VisualScriptEditor::_graph_ofs_changed(const Vector2 &p_ofs) {	if (updating_graph || !script.is_valid()) {		return;	}	updating_graph = true;	script->set_scroll(graph->get_scroll_ofs() / EDSCALE);	script->set_edited(true);	updating_graph = false;}void VisualScriptEditor::_comment_node_resized(const Vector2 &p_new_size, int p_node) {	if (updating_graph) {		return;	}	Ref<VisualScriptComment> vsc = script->get_node(p_node);	if (vsc.is_null()) {		return;	}	Node *node = graph->get_node(itos(p_node));	GraphNode *gn = Object::cast_to<GraphNode>(node);	if (!gn) {		return;	}	Vector2 new_size = p_new_size;	if (graph->is_using_snap()) {		Vector2 snap = Vector2(graph->get_snap(), graph->get_snap());		Vector2 min_size = (gn->get_minimum_size() + (snap * 0.5)).snapped(snap);		new_size = new_size.snapped(snap).max(min_size);	}	updating_graph = true;	graph->set_block_minimum_size_adjust(true); //faster resize	undo_redo->create_action(TTR("Resize Comment"), UndoRedo::MERGE_ENDS);	undo_redo->add_do_method(vsc.ptr(), "set_size", new_size / EDSCALE);	undo_redo->add_undo_method(vsc.ptr(), "set_size", vsc->get_size());	undo_redo->commit_action();	gn->set_custom_minimum_size(new_size);	gn->set_size(Size2(1, 1));	graph->set_block_minimum_size_adjust(false);	updating_graph = false;}void VisualScriptEditor::_menu_option(int p_what) {	switch (p_what) {		case EDIT_DELETE_NODES: {			_on_nodes_delete();		} break;		case EDIT_TOGGLE_BREAKPOINT: {			List<String> reselect;			for (int i = 0; i < graph->get_child_count(); i++) {				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));				if (gn) {					if (gn->is_selected()) {						int id = String(gn->get_name()).to_int();						Ref<VisualScriptNode> vsn = script->get_node(id);						if (vsn.is_valid()) {							vsn->set_breakpoint(!vsn->is_breakpoint());							reselect.push_back(gn->get_name());						}					}				}			}			_update_graph();			for (const String &E : reselect) {				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(E));				gn->set_selected(true);			}		} break;		case EDIT_FIND_NODE_TYPE: {			_generic_search(script->get_instance_base_type());		} break;		case EDIT_COPY_NODES:		case EDIT_CUT_NODES: {			clipboard->nodes.clear();			clipboard->data_connections.clear();			clipboard->sequence_connections.clear();			for (int i = 0; i < graph->get_child_count(); i++) {				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));				if (gn) {					if (gn->is_selected()) {						int id = gn->get_name().operator String().to_int();						Ref<VisualScriptNode> node = script->get_node(id);						if (Object::cast_to<VisualScriptFunction>(*node)) {							EditorNode::get_singleton()->show_warning(TTR("Can't copy the function node."));							return;						}						if (node.is_valid()) {							clipboard->nodes[id] = node->duplicate(true);							clipboard->nodes_positions[id] = script->get_node_position(id);						}					}				}			}			if (clipboard->nodes.is_empty()) {				break;			}			List<VisualScript::SequenceConnection> sequence_connections;			script->get_sequence_connection_list(&sequence_connections);			for (const VisualScript::SequenceConnection &E : sequence_connections) {				if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) {					clipboard->sequence_connections.insert(E);				}			}			List<VisualScript::DataConnection> data_connections;			script->get_data_connection_list(&data_connections);			for (const VisualScript::DataConnection &E : data_connections) {				if (clipboard->nodes.has(E.from_node) && clipboard->nodes.has(E.to_node)) {					clipboard->data_connections.insert(E);				}			}			if (p_what == EDIT_CUT_NODES) {				_on_nodes_delete(); // oh yeah, also delete on cut			}		} break;		case EDIT_PASTE_NODES: {			if (clipboard->nodes.is_empty()) {				EditorNode::get_singleton()->show_warning(TTR("Clipboard is empty!"));				break;			}			Map<int, int> remap;			undo_redo->create_action(TTR("Paste VisualScript Nodes"));			int idc = script->get_available_id() + 1;			Set<int> to_select;			Set<Vector2> existing_positions;			{				List<int> nodes;				script->get_node_list(&nodes);				for (int &E : nodes) {					Vector2 pos = script->get_node_position(E).snapped(Vector2(2, 2));					existing_positions.insert(pos);				}			}			for (Map<int, Ref<VisualScriptNode>>::Element *E = clipboard->nodes.front(); E; E = E->next()) {				Ref<VisualScriptNode> node = E->get()->duplicate();				int new_id = idc++;				to_select.insert(new_id);				remap[E->key()] = new_id;				Vector2 paste_pos = clipboard->nodes_positions[E->key()];				while (existing_positions.has(paste_pos.snapped(Vector2(2, 2)))) {					paste_pos += Vector2(20, 20) * EDSCALE;				}				undo_redo->add_do_method(script.ptr(), "add_node", new_id, node, paste_pos);				undo_redo->add_undo_method(script.ptr(), "remove_node", new_id);			}			for (Set<VisualScript::SequenceConnection>::Element *E = clipboard->sequence_connections.front(); E; E = E->next()) {				undo_redo->add_do_method(script.ptr(), "sequence_connect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);				undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", remap[E->get().from_node], E->get().from_output, remap[E->get().to_node]);			}			for (Set<VisualScript::DataConnection>::Element *E = clipboard->data_connections.front(); E; E = E->next()) {				undo_redo->add_do_method(script.ptr(), "data_connect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);				undo_redo->add_undo_method(script.ptr(), "data_disconnect", remap[E->get().from_node], E->get().from_port, remap[E->get().to_node], E->get().to_port);			}			undo_redo->add_do_method(this, "_update_graph");			undo_redo->add_undo_method(this, "_update_graph");			undo_redo->commit_action();			for (int i = 0; i < graph->get_child_count(); i++) {				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));				if (gn) {					int id = gn->get_name().operator String().to_int();					gn->set_selected(to_select.has(id));				}			}		} break;		case EDIT_CREATE_FUNCTION: {			// Create Function.			Map<int, Ref<VisualScriptNode>> nodes;			Set<int> selections;			for (int i = 0; i < graph->get_child_count(); i++) {				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(i));				if (gn) {					if (gn->is_selected()) {						int id = String(gn->get_name()).to_int();						Ref<VisualScriptNode> node = script->get_node(id);						if (Object::cast_to<VisualScriptFunction>(*node)) {							EditorNode::get_singleton()->show_warning(TTR("Can't create function with a function node."));							return;						}						if (node.is_valid()) {							nodes.insert(id, node);							selections.insert(id);						}					}				}			}			if (nodes.size() == 0) {				return; // nothing to be done if there are no valid nodes selected			}			Set<VisualScript::SequenceConnection> seqmove;			Set<VisualScript::DataConnection> datamove;			Set<VisualScript::SequenceConnection> seqext;			Set<VisualScript::DataConnection> dataext;			int start_node = -1;			Set<int> end_nodes;			if (nodes.size() == 1) {				Ref<VisualScriptNode> nd = script->get_node(nodes.front()->key());				if (nd.is_valid() && nd->has_input_sequence_port()) {					start_node = nodes.front()->key();				} else {					EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));					return;				}			} else {				List<VisualScript::SequenceConnection> seqs;				script->get_sequence_connection_list(&seqs);				if (seqs.size() == 0) {					// In case there are no sequence connections,					// select the top most node cause that's probably how,					// the user wants to connect the nodes.					int top_nd = -1;					Vector2 top;					for (Map<int, Ref<VisualScriptNode>>::Element *E = nodes.front(); E; E = E->next()) {						Ref<VisualScriptNode> nd = script->get_node(E->key());						if (nd.is_valid() && nd->has_input_sequence_port()) {							if (top_nd < 0) {								top_nd = E->key();								top = script->get_node_position(top_nd);							}							Vector2 pos = script->get_node_position(E->key());							if (top.y > pos.y) {								top_nd = E->key();								top = pos;							}						}					}					Ref<VisualScriptNode> nd = script->get_node(top_nd);					if (nd.is_valid() && nd->has_input_sequence_port()) {						start_node = top_nd;					} else {						EditorNode::get_singleton()->show_warning(TTR("Select at least one node with sequence port."));						return;					}				} else {					// Pick the node with input sequence.					Set<int> nodes_from;					Set<int> nodes_to;					for (const VisualScript::SequenceConnection &E : seqs) {						if (nodes.has(E.from_node) && nodes.has(E.to_node)) {							seqmove.insert(E);							nodes_from.insert(E.from_node);						} else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) {							seqext.insert(E);						} else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) {							if (start_node == -1) {								seqext.insert(E);								start_node = E.to_node;							} else {								EditorNode::get_singleton()->show_warning(TTR("Try to only have one sequence input in selection."));								return;							}						}						nodes_to.insert(E.to_node);					}					// To use to add return nodes.					_get_ends(start_node, seqs, selections, end_nodes);					if (start_node == -1) {						// If we still don't have a start node then,						// run through the nodes and select the first tree node,						// i.e. node without any input sequence but output sequence.						for (Set<int>::Element *E = nodes_from.front(); E; E = E->next()) {							if (!nodes_to.has(E->get())) {								start_node = E->get();							}						}					}				}			}			if (start_node == -1) {				return; // This should not happen, but just in case something goes wrong.			}			List<Variant::Type> inputs; // input types			List<Pair<int, int>> input_connections;			{				List<VisualScript::DataConnection> dats;				script->get_data_connection_list(&dats);				for (const VisualScript::DataConnection &E : dats) {					if (nodes.has(E.from_node) && nodes.has(E.to_node)) {						datamove.insert(E);					} else if (!nodes.has(E.from_node) && nodes.has(E.to_node)) {						// Add all these as inputs for the Function.						Ref<VisualScriptNode> node = script->get_node(E.to_node);						if (node.is_valid()) {							dataext.insert(E);							PropertyInfo pi = node->get_input_value_port_info(E.to_port);							inputs.push_back(pi.type);							input_connections.push_back(Pair<int, int>(E.to_node, E.to_port));						}					} else if (nodes.has(E.from_node) && !nodes.has(E.to_node)) {						dataext.insert(E);					}				}			}			int fn_id = script->get_available_id();			{				String new_fn = _validate_name("new_function");				Vector2 pos = _get_available_pos(false, script->get_node_position(start_node) - Vector2(80, 150));				Ref<VisualScriptFunction> func_node;				func_node.instantiate();				func_node->set_name(new_fn);				undo_redo->create_action(TTR("Create Function"));				undo_redo->add_do_method(script.ptr(), "add_function", new_fn, fn_id);				undo_redo->add_do_method(script.ptr(), "add_node", fn_id, func_node, pos);				undo_redo->add_undo_method(script.ptr(), "remove_function", new_fn);				undo_redo->add_undo_method(script.ptr(), "remove_node", fn_id);				undo_redo->add_do_method(this, "_update_members");				undo_redo->add_undo_method(this, "_update_members");				undo_redo->add_do_method(this, "emit_signal", "edited_script_changed");				undo_redo->add_undo_method(this, "emit_signal", "edited_script_changed");				// Might make the system more intelligent by checking port from info.				int i = 0;				List<Pair<int, int>>::Element *F = input_connections.front();				for (List<Variant::Type>::Element *E = inputs.front(); E && F; E = E->next(), F = F->next()) {					func_node->add_argument(E->get(), "arg_" + String::num_int64(i), i);					undo_redo->add_do_method(script.ptr(), "data_connect", fn_id, i, F->get().first, F->get().second);					i++; // increment i				}				// Ensure Preview Selection is of newly created function node.				if (selections.size()) {					EditorNode::get_singleton()->push_item(func_node.ptr());				}			}			// Move the nodes.			// Handles reconnection of sequence connections on undo, start here in case of issues.			for (Set<VisualScript::SequenceConnection>::Element *E = seqext.front(); E; E = E->next()) {				undo_redo->add_do_method(script.ptr(), "sequence_disconnect", E->get().from_node, E->get().from_output, E->get().to_node);				undo_redo->add_undo_method(script.ptr(), "sequence_connect", E->get().from_node, E->get().from_output, E->get().to_node);			}			for (Set<VisualScript::DataConnection>::Element *E = dataext.front(); E; E = E->next()) {				undo_redo->add_do_method(script.ptr(), "data_disconnect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);				undo_redo->add_undo_method(script.ptr(), "data_connect", E->get().from_node, E->get().from_port, E->get().to_node, E->get().to_port);			}			// I don't really think we need support for non sequenced functions at this moment.			undo_redo->add_do_method(script.ptr(), "sequence_connect", fn_id, 0, start_node);			// Could fail with the new changes, start here when searching for bugs in create function shortcut.			int m = 1;			for (Set<int>::Element *G = end_nodes.front(); G; G = G->next()) {				Ref<VisualScriptReturn> ret_node;				ret_node.instantiate();				int ret_id = fn_id + (m++);				selections.insert(ret_id);				Vector2 posi = _get_available_pos(false, script->get_node_position(G->get()) + Vector2(80, -100));				undo_redo->add_do_method(script.ptr(), "add_node", ret_id, ret_node, posi);				undo_redo->add_undo_method(script.ptr(), "remove_node", ret_id);				undo_redo->add_do_method(script.ptr(), "sequence_connect", G->get(), 0, ret_id);				// Add data outputs from each of the end_nodes.				Ref<VisualScriptNode> vsn = script->get_node(G->get());				if (vsn.is_valid() && vsn->get_output_value_port_count() > 0) {					ret_node->set_enable_return_value(true);					// Use the zeroth data port cause that's the likely one that is planned to be used.					ret_node->set_return_type(vsn->get_output_value_port_info(0).type);					undo_redo->add_do_method(script.ptr(), "data_connect", G->get(), 0, ret_id, 0);				}			}			undo_redo->add_do_method(this, "_update_graph");			undo_redo->add_undo_method(this, "_update_graph");			undo_redo->commit_action();			// Make sure all Nodes get marked for selection so that they can be moved together.			selections.insert(fn_id);			for (int k = 0; k < graph->get_child_count(); k++) {				GraphNode *gn = Object::cast_to<GraphNode>(graph->get_child(k));				if (gn) {					int id = gn->get_name().operator String().to_int();					gn->set_selected(selections.has(id));				}			}		} break;		case REFRESH_GRAPH: {			_update_graph();		} break;	}}// This is likely going to be very slow and I am not sure if I should keep it,// but I hope that it will not be a problem considering that we won't be creating functions so frequently,// and cyclic connections would be a problem but hopefully we won't let them get to this point.void VisualScriptEditor::_get_ends(int p_node, const List<VisualScript::SequenceConnection> &p_seqs, const Set<int> &p_selected, Set<int> &r_end_nodes) {	for (const VisualScript::SequenceConnection &E : p_seqs) {		int from = E.from_node;		int to = E.to_node;		if (from == p_node && p_selected.has(to)) {			// This is an interior connection move forward to the to node.			_get_ends(to, p_seqs, p_selected, r_end_nodes);		} else if (from == p_node && !p_selected.has(to)) {			r_end_nodes.insert(from);		}	}}void VisualScriptEditor::_member_rmb_selected(const Vector2 &p_pos) {	TreeItem *ti = members->get_selected();	ERR_FAIL_COND(!ti);	member_popup->clear();	member_popup->set_position(members->get_global_position() + p_pos);	member_popup->set_size(Vector2());	function_name_edit->set_position(members->get_global_position() + p_pos);	function_name_edit->set_size(Vector2());	TreeItem *root = members->get_root();	Ref<Texture2D> del_icon = Control::get_theme_icon(SNAME("Remove"), SNAME("EditorIcons"));	Ref<Texture2D> edit_icon = Control::get_theme_icon(SNAME("Edit"), SNAME("EditorIcons"));	if (ti->get_parent() == root->get_first_child()) {		member_type = MEMBER_FUNCTION;		member_name = ti->get_text(0);		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);		member_popup->add_separator();		member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);		member_popup->popup();		return;	}	if (ti->get_parent() == root->get_first_child()->get_next()) {		member_type = MEMBER_VARIABLE;		member_name = ti->get_text(0);		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);		member_popup->add_separator();		member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);		member_popup->popup();		return;	}	if (ti->get_parent() == root->get_first_child()->get_next()->get_next()) {		member_type = MEMBER_SIGNAL;		member_name = ti->get_text(0);		member_popup->add_icon_shortcut(edit_icon, ED_GET_SHORTCUT("visual_script_editor/edit_member"), MEMBER_EDIT);		member_popup->add_separator();		member_popup->add_icon_shortcut(del_icon, ED_GET_SHORTCUT("ui_graph_delete"), MEMBER_REMOVE);		member_popup->popup();		return;	}}void VisualScriptEditor::_member_option(int p_option) {	switch (member_type) {		case MEMBER_FUNCTION: {			if (p_option == MEMBER_REMOVE) {				// Delete the function.				String name = member_name;				List<String> lst;				int fn_node = script->get_function_node_id(name);				undo_redo->create_action(TTR("Remove Function"));				undo_redo->add_do_method(script.ptr(), "remove_function", name);				undo_redo->add_do_method(script.ptr(), "remove_node", fn_node);				undo_redo->add_undo_method(script.ptr(), "add_function", name, fn_node);				undo_redo->add_undo_method(script.ptr(), "add_node", fn_node, script->get_node(fn_node), script->get_node_position(fn_node));				List<VisualScript::SequenceConnection> seqcons;				script->get_sequence_connection_list(&seqcons);				for (const VisualScript::SequenceConnection &E : seqcons) {					if (E.from_node == fn_node) {						undo_redo->add_undo_method(script.ptr(), "sequence_connect", fn_node, E.from_output, E.to_node);					}				}				List<VisualScript::DataConnection> datcons;				script->get_data_connection_list(&datcons);				for (const VisualScript::DataConnection &E : datcons) {					if (E.from_node == fn_node) {						undo_redo->add_undo_method(script.ptr(), "data_connect", fn_node, E.from_port, E.to_node, E.to_port);					}				}				undo_redo->add_do_method(this, "_update_members");				undo_redo->add_undo_method(this, "_update_members");				undo_redo->add_do_method(this, "_update_graph");				undo_redo->add_undo_method(this, "_update_graph");				undo_redo->commit_action();			} else if (p_option == MEMBER_EDIT) {				selected = members->get_selected()->get_text(0);				function_name_edit->popup();				function_name_box->set_text(selected);				function_name_box->select_all();			}		} break;		case MEMBER_VARIABLE: {			String name = member_name;			if (p_option == MEMBER_REMOVE) {				undo_redo->create_action(TTR("Remove Variable"));				undo_redo->add_do_method(script.ptr(), "remove_variable", name);				undo_redo->add_undo_method(script.ptr(), "add_variable", name, script->get_variable_default_value(name));				undo_redo->add_undo_method(script.ptr(), "set_variable_info", name, script->call("get_variable_info", name)); //return as dict				undo_redo->add_do_method(this, "_update_members");				undo_redo->add_undo_method(this, "_update_members");				undo_redo->commit_action();			} else if (p_option == MEMBER_EDIT) {				variable_editor->edit(name);				edit_variable_dialog->set_title(TTR("Editing Variable:") + " " + name);				edit_variable_dialog->popup_centered(Size2(400, 200) * EDSCALE);			}		} break;		case MEMBER_SIGNAL: {			String name = member_name;			if (p_option == MEMBER_REMOVE) {				undo_redo->create_action(TTR("Remove Signal"));				undo_redo->add_do_method(script.ptr(), "remove_custom_signal", name);				undo_redo->add_undo_method(script.ptr(), "add_custom_signal", name);				for (int i = 0; i < script->custom_signal_get_argument_count(name); i++) {					undo_redo->add_undo_method(script.ptr(), "custom_signal_add_argument", name, script->custom_signal_get_argument_name(name, i), script->custom_signal_get_argument_type(name, i));				}				undo_redo->add_do_method(this, "_update_members");				undo_redo->add_undo_method(this, "_update_members");				undo_redo->commit_action();			} else if (p_option == MEMBER_EDIT) {				signal_editor->edit(name);				edit_signal_dialog->set_title(TTR("Editing Signal:") + " " + name);				edit_signal_dialog->popup_centered(Size2(400, 300) * EDSCALE);			}		} break;	}}void VisualScriptEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) {}void VisualScriptEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) {}void VisualScriptEditor::_bind_methods() {	ClassDB::bind_method("_move_node", &VisualScriptEditor::_move_node);	ClassDB::bind_method("_update_graph", &VisualScriptEditor::_update_graph, DEFVAL(-1));	ClassDB::bind_method("_center_on_node", &VisualScriptEditor::_center_on_node);	ClassDB::bind_method("_button_resource_previewed", &VisualScriptEditor::_button_resource_previewed);	ClassDB::bind_method("_port_action_menu", &VisualScriptEditor::_port_action_menu);	ClassDB::bind_method("_create_new_node_from_name", &VisualScriptEditor::_create_new_node_from_name);	ClassDB::bind_method("_get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw);	ClassDB::bind_method("_can_drop_data_fw", &VisualScriptEditor::can_drop_data_fw);	ClassDB::bind_method("_drop_data_fw", &VisualScriptEditor::drop_data_fw);	ClassDB::bind_method("_input", &VisualScriptEditor::_input);	ClassDB::bind_method("_update_graph_connections", &VisualScriptEditor::_update_graph_connections);	ClassDB::bind_method("_update_members", &VisualScriptEditor::_update_members);	ClassDB::bind_method("_generic_search", &VisualScriptEditor::_generic_search);	ClassDB::bind_method(D_METHOD("add_syntax_highlighter", "highlighter"), &VisualScriptEditor::add_syntax_highlighter);}VisualScriptEditor::VisualScriptEditor() {	if (!clipboard) {		clipboard = memnew(Clipboard);	}	updating_graph = false;	saved_pos_dirty = false;	saved_position = Vector2(0, 0);	edit_menu = memnew(MenuButton);	edit_menu->set_shortcut_context(this);	edit_menu->set_text(TTR("Edit"));	edit_menu->set_switch_on_hover(true);	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_graph_delete"), EDIT_DELETE_NODES);	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/toggle_breakpoint"), EDIT_TOGGLE_BREAKPOINT);	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/find_node_type"), EDIT_FIND_NODE_TYPE);	edit_menu->get_popup()->add_separator();	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_copy"), EDIT_COPY_NODES);	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_cut"), EDIT_CUT_NODES);	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("ui_paste"), EDIT_PASTE_NODES);	edit_menu->get_popup()->add_separator();	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/create_function"), EDIT_CREATE_FUNCTION);	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("visual_script_editor/refresh_nodes"), REFRESH_GRAPH);	edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_menu_option));	members_section = memnew(VBoxContainer);	// Add but wait until done setting up this.	ScriptEditor::get_singleton()->get_left_list_split()->call_deferred(SNAME("add_child"), members_section);	members_section->set_v_size_flags(SIZE_EXPAND_FILL);	CheckButton *tool_script_check = memnew(CheckButton);	tool_script_check->set_text(TTR("Make Tool:"));	members_section->add_child(tool_script_check);	tool_script_check->connect("pressed", callable_mp(this, &VisualScriptEditor::_toggle_tool_script));	///       Members        ///	members = memnew(Tree);	members_section->add_margin_child(TTR("Members:"), members, true);	members->set_custom_minimum_size(Size2(0, 50 * EDSCALE));	members->set_hide_root(true);	members->connect("button_pressed", callable_mp(this, &VisualScriptEditor::_member_button));	members->connect("item_edited", callable_mp(this, &VisualScriptEditor::_member_edited));	members->connect("cell_selected", callable_mp(this, &VisualScriptEditor::_member_selected), varray(), CONNECT_DEFERRED);	members->connect("gui_input", callable_mp(this, &VisualScriptEditor::_members_gui_input));	members->connect("item_rmb_selected", callable_mp(this, &VisualScriptEditor::_member_rmb_selected));	members->set_allow_rmb_select(true);	members->set_allow_reselect(true);	members->set_hide_folding(true);	members->set_drag_forwarding(this);	member_popup = memnew(PopupMenu);	add_child(member_popup);	member_popup->connect("id_pressed", callable_mp(this, &VisualScriptEditor::_member_option));	function_name_edit = memnew(AcceptDialog);	function_name_box = memnew(LineEdit);	function_name_edit->add_child(function_name_box);	function_name_box->connect("gui_input", callable_mp(this, &VisualScriptEditor::_fn_name_box_input));	function_name_box->set_expand_to_text_length_enabled(true);	add_child(function_name_edit);	///       Actual Graph          ///	graph = memnew(GraphEdit);	add_child(graph);	graph->set_v_size_flags(Control::SIZE_EXPAND_FILL);	graph->set_anchors_and_offsets_preset(Control::PRESET_WIDE);	graph->connect("node_selected", callable_mp(this, &VisualScriptEditor::_node_selected));	graph->connect("begin_node_move", callable_mp(this, &VisualScriptEditor::_begin_node_move));	graph->connect("end_node_move", callable_mp(this, &VisualScriptEditor::_end_node_move));	graph->connect("delete_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_delete));	graph->connect("duplicate_nodes_request", callable_mp(this, &VisualScriptEditor::_on_nodes_duplicate));	graph->connect("gui_input", callable_mp(this, &VisualScriptEditor::_graph_gui_input));	graph->set_drag_forwarding(this);	float graph_minimap_opacity = EditorSettings::get_singleton()->get("editors/visual_editors/minimap_opacity");	graph->set_minimap_opacity(graph_minimap_opacity);	graph->hide();	graph->connect("scroll_offset_changed", callable_mp(this, &VisualScriptEditor::_graph_ofs_changed));	/// Add Buttons to Top Bar/Zoom bar.	HBoxContainer *graph_hbc = graph->get_zoom_hbox();	Label *base_lbl = memnew(Label);	base_lbl->set_text(TTR("Change Base Type:") + " ");	graph_hbc->add_child(base_lbl);	base_type_select = memnew(Button);	base_type_select->connect("pressed", callable_mp(this, &VisualScriptEditor::_change_base_type));	graph_hbc->add_child(base_type_select);	Button *add_nds = memnew(Button);	add_nds->set_text(TTR("Add Nodes..."));	graph_hbc->add_child(add_nds);	add_nds->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_node_dialog));	Button *fn_btn = memnew(Button);	fn_btn->set_text(TTR("Add Function..."));	graph_hbc->add_child(fn_btn);	fn_btn->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function_dialog));	// Add Function Dialog.	VBoxContainer *function_vb = memnew(VBoxContainer);	function_vb->set_v_size_flags(SIZE_EXPAND_FILL);	function_vb->set_custom_minimum_size(Size2(450, 300) * EDSCALE);	HBoxContainer *func_name_hbox = memnew(HBoxContainer);	function_vb->add_child(func_name_hbox);	Label *func_name_label = memnew(Label);	func_name_label->set_text(TTR("Name:"));	func_name_hbox->add_child(func_name_label);	func_name_box = memnew(LineEdit);	func_name_box->set_h_size_flags(SIZE_EXPAND_FILL);	func_name_box->set_placeholder(TTR("function_name"));	func_name_box->set_text("");	func_name_box->connect("focus_entered", callable_mp(this, &VisualScriptEditor::_deselect_input_names));	func_name_hbox->add_child(func_name_box);	// Add minor setting for function if needed, here!	function_vb->add_child(memnew(HSeparator));	Button *add_input_button = memnew(Button);	add_input_button->set_h_size_flags(SIZE_EXPAND_FILL);	add_input_button->set_text(TTR("Add Input"));	add_input_button->connect("pressed", callable_mp(this, &VisualScriptEditor::_add_func_input));	function_vb->add_child(add_input_button);	func_input_scroll = memnew(ScrollContainer);	func_input_scroll->set_v_size_flags(SIZE_EXPAND_FILL);	function_vb->add_child(func_input_scroll);	func_input_vbox = memnew(VBoxContainer);	func_input_vbox->set_h_size_flags(SIZE_EXPAND_FILL);	func_input_scroll->add_child(func_input_vbox);	function_create_dialog = memnew(ConfirmationDialog);	function_create_dialog->set_title(TTR("Create Function"));	function_create_dialog->add_child(function_vb);	function_create_dialog->get_ok_button()->set_text(TTR("Create"));	function_create_dialog->get_ok_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_create_function));	add_child(function_create_dialog);	select_func_text = memnew(Label);	select_func_text->set_text(TTR("Select or create a function to edit its graph."));	select_func_text->set_align(Label::ALIGN_CENTER);	select_func_text->set_valign(Label::VALIGN_CENTER);	select_func_text->set_h_size_flags(SIZE_EXPAND_FILL);	add_child(select_func_text);	hint_text = memnew(Label);	hint_text->set_anchor_and_offset(SIDE_TOP, ANCHOR_END, -100);	hint_text->set_anchor_and_offset(SIDE_BOTTOM, ANCHOR_END, 0);	hint_text->set_anchor_and_offset(SIDE_RIGHT, ANCHOR_END, 0);	hint_text->set_align(Label::ALIGN_CENTER);	hint_text->set_valign(Label::VALIGN_CENTER);	graph->add_child(hint_text);	hint_text_timer = memnew(Timer);	hint_text_timer->set_wait_time(4);	hint_text_timer->connect("timeout", callable_mp(this, &VisualScriptEditor::_hide_timer));	add_child(hint_text_timer);	// Allowed casts (connections).	for (int i = 0; i < Variant::VARIANT_MAX; i++) {		graph->add_valid_connection_type(Variant::NIL, i);		graph->add_valid_connection_type(i, Variant::NIL);		for (int j = 0; j < Variant::VARIANT_MAX; j++) {			if (Variant::can_convert(Variant::Type(i), Variant::Type(j))) {				graph->add_valid_connection_type(i, j);			}		}		graph->add_valid_right_disconnect_type(i);	}	graph->add_valid_left_disconnect_type(TYPE_SEQUENCE);	graph->connect("connection_request", callable_mp(this, &VisualScriptEditor::_graph_connected));	graph->connect("disconnection_request", callable_mp(this, &VisualScriptEditor::_graph_disconnected));	graph->connect("connection_to_empty", callable_mp(this, &VisualScriptEditor::_graph_connect_to_empty));	edit_signal_dialog = memnew(AcceptDialog);	edit_signal_dialog->get_ok_button()->set_text(TTR("Close"));	add_child(edit_signal_dialog);	signal_editor = memnew(VisualScriptEditorSignalEdit);	edit_signal_edit = memnew(EditorInspector);	edit_signal_dialog->add_child(edit_signal_edit);	edit_signal_edit->edit(signal_editor);	edit_variable_dialog = memnew(AcceptDialog);	edit_variable_dialog->get_ok_button()->set_text(TTR("Close"));	add_child(edit_variable_dialog);	variable_editor = memnew(VisualScriptEditorVariableEdit);	edit_variable_edit = memnew(EditorInspector);	edit_variable_dialog->add_child(edit_variable_edit);	edit_variable_edit->edit(variable_editor);	select_base_type = memnew(CreateDialog);	select_base_type->set_base_type("Object"); // Anything goes.	select_base_type->connect("create", callable_mp(this, &VisualScriptEditor::_change_base_type_callback));	add_child(select_base_type);	undo_redo = EditorNode::get_singleton()->get_undo_redo();	updating_members = false;	set_process_input(true);	default_value_edit = memnew(CustomPropertyEditor);	add_child(default_value_edit);	default_value_edit->connect("variant_changed", callable_mp(this, &VisualScriptEditor::_default_value_changed));	new_connect_node_select = memnew(VisualScriptPropertySelector);	add_child(new_connect_node_select);	new_connect_node_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_connect_node));	new_connect_node_select->get_cancel_button()->connect("pressed", callable_mp(this, &VisualScriptEditor::_cancel_connect_node));	new_virtual_method_select = memnew(VisualScriptPropertySelector);	add_child(new_virtual_method_select);	new_virtual_method_select->connect("selected", callable_mp(this, &VisualScriptEditor::_selected_new_virtual_method));}VisualScriptEditor::~VisualScriptEditor() {	undo_redo->clear_history(); // Avoid crashes.	memdelete(signal_editor);	memdelete(variable_editor);}static ScriptEditorBase *create_editor(const RES &p_resource) {	if (Object::cast_to<VisualScript>(*p_resource)) {		return memnew(VisualScriptEditor);	}	return nullptr;}VisualScriptEditor::Clipboard *VisualScriptEditor::clipboard = nullptr;void VisualScriptEditor::free_clipboard() {	if (clipboard) {		memdelete(clipboard);	}}static void register_editor_callback() {	ScriptEditor::register_create_script_editor_function(create_editor);	ED_SHORTCUT("visual_script_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);	ED_SHORTCUT("visual_script_editor/find_node_type", TTR("Find Node Type"), KEY_MASK_CMD + KEY_F);	ED_SHORTCUT("visual_script_editor/create_function", TTR("Make Function"), KEY_MASK_CMD + KEY_G);	ED_SHORTCUT("visual_script_editor/refresh_nodes", TTR("Refresh Graph"), KEY_MASK_CMD + KEY_R);	ED_SHORTCUT("visual_script_editor/edit_member", TTR("Edit Member"), KEY_MASK_CMD + KEY_E);}void VisualScriptEditor::register_editor() {	// Too early to register stuff here, request a callback.	EditorNode::add_plugin_init_callback(register_editor_callback);}Ref<VisualScriptNode> _VisualScriptEditor::create_node_custom(const String &p_name) {	Ref<VisualScriptCustomNode> node;	node.instantiate();	node->set_script(singleton->custom_nodes[p_name]);	return node;}_VisualScriptEditor *_VisualScriptEditor::singleton = nullptr;Map<String, REF> _VisualScriptEditor::custom_nodes;_VisualScriptEditor::_VisualScriptEditor() {	singleton = this;}_VisualScriptEditor::~_VisualScriptEditor() {	custom_nodes.clear();}void _VisualScriptEditor::add_custom_node(const String &p_name, const String &p_category, const Ref<Script> &p_script) {	String node_name = "custom/" + p_category + "/" + p_name;	custom_nodes.insert(node_name, p_script);	VisualScriptLanguage::singleton->add_register_func(node_name, &_VisualScriptEditor::create_node_custom);	emit_signal(SNAME("custom_nodes_updated"));}void _VisualScriptEditor::remove_custom_node(const String &p_name, const String &p_category) {	String node_name = "custom/" + p_category + "/" + p_name;	custom_nodes.erase(node_name);	VisualScriptLanguage::singleton->remove_register_func(node_name);	emit_signal(SNAME("custom_nodes_updated"));}void _VisualScriptEditor::_bind_methods() {	ClassDB::bind_method(D_METHOD("add_custom_node", "name", "category", "script"), &_VisualScriptEditor::add_custom_node);	ClassDB::bind_method(D_METHOD("remove_custom_node", "name", "category"), &_VisualScriptEditor::remove_custom_node);	ADD_SIGNAL(MethodInfo("custom_nodes_updated"));}void VisualScriptEditor::validate() {}#endif
 |