script_editor_plugin.cpp 64 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451
  1. /*************************************************************************/
  2. /* script_editor_plugin.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* http://www.godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* */
  10. /* Permission is hereby granted, free of charge, to any person obtaining */
  11. /* a copy of this software and associated documentation files (the */
  12. /* "Software"), to deal in the Software without restriction, including */
  13. /* without limitation the rights to use, copy, modify, merge, publish, */
  14. /* distribute, sublicense, and/or sell copies of the Software, and to */
  15. /* permit persons to whom the Software is furnished to do so, subject to */
  16. /* the following conditions: */
  17. /* */
  18. /* The above copyright notice and this permission notice shall be */
  19. /* included in all copies or substantial portions of the Software. */
  20. /* */
  21. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  22. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  23. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  24. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  25. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  26. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  27. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  28. /*************************************************************************/
  29. #include "script_editor_plugin.h"
  30. #include "tools/editor/editor_settings.h"
  31. #include "io/resource_loader.h"
  32. #include "io/resource_saver.h"
  33. #include "os/keyboard.h"
  34. #include "os/os.h"
  35. #include "tools/editor/editor_node.h"
  36. #include "tools/editor/script_editor_debugger.h"
  37. #include "globals.h"
  38. #include "os/file_access.h"
  39. #include "scene/main/viewport.h"
  40. #include "os/keyboard.h"
  41. #include "os/input.h"
  42. /*** SCRIPT EDITOR ****/
  43. void ScriptEditorBase::_bind_methods() {
  44. ADD_SIGNAL(MethodInfo("name_changed"));
  45. ADD_SIGNAL(MethodInfo("request_help_search",PropertyInfo(Variant::STRING,"topic")));
  46. ADD_SIGNAL(MethodInfo("request_open_script_at_line",PropertyInfo(Variant::OBJECT,"script"),PropertyInfo(Variant::INT,"line")));
  47. ADD_SIGNAL(MethodInfo("request_save_history"));
  48. ADD_SIGNAL(MethodInfo("go_to_help",PropertyInfo(Variant::STRING,"what")));
  49. }
  50. static bool _can_open_in_editor(Script* p_script) {
  51. String path = p_script->get_path();
  52. if (path.find("::")!=-1) {
  53. //refuse handling this if it can't be edited
  54. bool valid=false;
  55. for(int i=0;i<EditorNode::get_singleton()->get_editor_data().get_edited_scene_count();i++) {
  56. if (path.begins_with(EditorNode::get_singleton()->get_editor_data().get_scene_path(i))) {
  57. valid=true;
  58. break;
  59. }
  60. }
  61. return valid;
  62. }
  63. return true;
  64. }
  65. class EditorScriptCodeCompletionCache : public ScriptCodeCompletionCache {
  66. struct Cache {
  67. uint64_t time_loaded;
  68. RES cache;
  69. };
  70. Map<String,Cache> cached;
  71. public:
  72. uint64_t max_time_cache;
  73. int max_cache_size;
  74. void cleanup() {
  75. List< Map<String,Cache>::Element * > to_clean;
  76. Map<String,Cache>::Element *I=cached.front();
  77. while(I) {
  78. if ((OS::get_singleton()->get_ticks_msec()-I->get().time_loaded)>max_time_cache) {
  79. to_clean.push_back(I);
  80. }
  81. I=I->next();
  82. }
  83. while(to_clean.front()) {
  84. cached.erase(to_clean.front()->get());
  85. to_clean.pop_front();
  86. }
  87. }
  88. RES get_cached_resource(const String& p_path) {
  89. Map<String,Cache>::Element *E=cached.find(p_path);
  90. if (!E) {
  91. Cache c;
  92. c.cache=ResourceLoader::load(p_path);
  93. E=cached.insert(p_path,c);
  94. }
  95. E->get().time_loaded=OS::get_singleton()->get_ticks_msec();
  96. if (cached.size()>max_cache_size) {
  97. uint64_t older;
  98. Map<String,Cache>::Element *O=cached.front();
  99. older=O->get().time_loaded;
  100. Map<String,Cache>::Element *I=O;
  101. while(I) {
  102. if (I->get().time_loaded<older) {
  103. older = I->get().time_loaded;
  104. O=I;
  105. }
  106. I=I->next();
  107. }
  108. if (O!=E) {//should never heppane..
  109. cached.erase(O);
  110. }
  111. }
  112. return E->get().cache;
  113. }
  114. EditorScriptCodeCompletionCache() {
  115. max_cache_size=128;
  116. max_time_cache=5*60*1000; //minutes, five
  117. }
  118. };
  119. #define SORT_SCRIPT_LIST
  120. void ScriptEditorQuickOpen::popup(const Vector<String>& p_functions, bool p_dontclear) {
  121. popup_centered_ratio(0.6);
  122. if (p_dontclear)
  123. search_box->select_all();
  124. else
  125. search_box->clear();
  126. search_box->grab_focus();
  127. functions=p_functions;
  128. _update_search();
  129. }
  130. void ScriptEditorQuickOpen::_text_changed(const String& p_newtext) {
  131. _update_search();
  132. }
  133. void ScriptEditorQuickOpen::_sbox_input(const InputEvent& p_ie) {
  134. if (p_ie.type==InputEvent::KEY && (
  135. p_ie.key.scancode == KEY_UP ||
  136. p_ie.key.scancode == KEY_DOWN ||
  137. p_ie.key.scancode == KEY_PAGEUP ||
  138. p_ie.key.scancode == KEY_PAGEDOWN ) ) {
  139. search_options->call("_gui_input",p_ie);
  140. search_box->accept_event();
  141. }
  142. }
  143. void ScriptEditorQuickOpen::_update_search() {
  144. search_options->clear();
  145. TreeItem *root = search_options->create_item();
  146. for(int i=0;i<functions.size();i++) {
  147. String file = functions[i];
  148. if ((search_box->get_text()=="" || file.findn(search_box->get_text())!=-1)) {
  149. TreeItem *ti = search_options->create_item(root);
  150. ti->set_text(0,file);
  151. if (root->get_children()==ti)
  152. ti->select(0);
  153. }
  154. }
  155. get_ok()->set_disabled(root->get_children()==NULL);
  156. }
  157. void ScriptEditorQuickOpen::_confirmed() {
  158. TreeItem *ti = search_options->get_selected();
  159. if (!ti)
  160. return;
  161. int line = ti->get_text(0).get_slice(":",1).to_int();
  162. emit_signal("goto_line",line-1);
  163. hide();
  164. }
  165. void ScriptEditorQuickOpen::_notification(int p_what) {
  166. if (p_what==NOTIFICATION_ENTER_TREE) {
  167. connect("confirmed",this,"_confirmed");
  168. }
  169. }
  170. void ScriptEditorQuickOpen::_bind_methods() {
  171. ClassDB::bind_method(_MD("_text_changed"),&ScriptEditorQuickOpen::_text_changed);
  172. ClassDB::bind_method(_MD("_confirmed"),&ScriptEditorQuickOpen::_confirmed);
  173. ClassDB::bind_method(_MD("_sbox_input"),&ScriptEditorQuickOpen::_sbox_input);
  174. ADD_SIGNAL(MethodInfo("goto_line",PropertyInfo(Variant::INT,"line")));
  175. }
  176. ScriptEditorQuickOpen::ScriptEditorQuickOpen() {
  177. VBoxContainer *vbc = memnew( VBoxContainer );
  178. add_child(vbc);
  179. //set_child_rect(vbc);
  180. search_box = memnew( LineEdit );
  181. vbc->add_margin_child(TTR("Search:"),search_box);
  182. search_box->connect("text_changed",this,"_text_changed");
  183. search_box->connect("gui_input",this,"_sbox_input");
  184. search_options = memnew( Tree );
  185. vbc->add_margin_child(TTR("Matches:"),search_options,true);
  186. get_ok()->set_text(TTR("Open"));
  187. get_ok()->set_disabled(true);
  188. register_text_enter(search_box);
  189. set_hide_on_ok(false);
  190. search_options->connect("item_activated",this,"_confirmed");
  191. search_options->set_hide_root(true);
  192. }
  193. /////////////////////////////////
  194. ScriptEditor *ScriptEditor::script_editor=NULL;
  195. /*** SCRIPT EDITOR ******/
  196. String ScriptEditor::_get_debug_tooltip(const String&p_text,Node *_se) {
  197. //ScriptEditorBase *se=_se->cast_to<ScriptEditorBase>();
  198. String val = debugger->get_var_value(p_text);
  199. if (val!=String()) {
  200. return p_text+": "+val;
  201. } else {
  202. return String();
  203. }
  204. }
  205. void ScriptEditor::_breaked(bool p_breaked,bool p_can_debug) {
  206. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_NEXT), !(p_breaked && p_can_debug));
  207. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), !(p_breaked && p_can_debug) );
  208. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), p_breaked );
  209. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), !p_breaked );
  210. for(int i=0;i<tab_container->get_child_count();i++) {
  211. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  212. if (!se) {
  213. continue;
  214. }
  215. se->set_debugger_active(p_breaked);
  216. }
  217. }
  218. void ScriptEditor::_show_debugger(bool p_show) {
  219. //debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), p_show);
  220. }
  221. void ScriptEditor::_script_created(Ref<Script> p_script) {
  222. editor->push_item(p_script.operator->());
  223. }
  224. void ScriptEditor::_goto_script_line2(int p_line) {
  225. int selected = tab_container->get_current_tab();
  226. if (selected<0 || selected>=tab_container->get_child_count())
  227. return;
  228. ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
  229. if (!current)
  230. return;
  231. current->goto_line(p_line);
  232. }
  233. void ScriptEditor::_goto_script_line(REF p_script,int p_line) {
  234. editor->push_item(p_script.ptr());
  235. int selected = tab_container->get_current_tab();
  236. if (selected<0 || selected>=tab_container->get_child_count())
  237. return;
  238. ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
  239. if (!current)
  240. return;
  241. current->goto_line(p_line,true);
  242. }
  243. void ScriptEditor::_update_history_arrows() {
  244. script_back->set_disabled( history_pos<=0 );
  245. script_forward->set_disabled( history_pos>=history.size()-1 );
  246. }
  247. void ScriptEditor::_save_history() {
  248. if (history_pos>=0 && history_pos<history.size() && history[history_pos].control==tab_container->get_current_tab_control()) {
  249. Node *n = tab_container->get_current_tab_control();
  250. if (n->cast_to<ScriptEditorBase>()) {
  251. history[history_pos].state=n->cast_to<ScriptEditorBase>()->get_edit_state();
  252. }
  253. if (n->cast_to<EditorHelp>()) {
  254. history[history_pos].state=n->cast_to<EditorHelp>()->get_scroll();
  255. }
  256. }
  257. history.resize(history_pos+1);
  258. ScriptHistory sh;
  259. sh.control=tab_container->get_current_tab_control();
  260. sh.state=Variant();
  261. history.push_back(sh);
  262. history_pos++;
  263. _update_history_arrows();
  264. }
  265. void ScriptEditor::_go_to_tab(int p_idx) {
  266. Node *cn = tab_container->get_child(p_idx);
  267. if (!cn)
  268. return;
  269. Control *c = cn->cast_to<Control>();
  270. if (!c)
  271. return;
  272. if (history_pos>=0 && history_pos<history.size() && history[history_pos].control==tab_container->get_current_tab_control()) {
  273. Node *n = tab_container->get_current_tab_control();
  274. if (n->cast_to<ScriptEditorBase>()) {
  275. history[history_pos].state=n->cast_to<ScriptEditorBase>()->get_edit_state();
  276. }
  277. if (n->cast_to<EditorHelp>()) {
  278. history[history_pos].state=n->cast_to<EditorHelp>()->get_scroll();
  279. }
  280. }
  281. history.resize(history_pos+1);
  282. ScriptHistory sh;
  283. sh.control=c;
  284. sh.state=Variant();
  285. history.push_back(sh);
  286. history_pos++;
  287. tab_container->set_current_tab(p_idx);
  288. c = tab_container->get_current_tab_control();
  289. if (c->cast_to<ScriptEditorBase>()) {
  290. script_name_label->set_text(c->cast_to<ScriptEditorBase>()->get_name());
  291. script_icon->set_texture(c->cast_to<ScriptEditorBase>()->get_icon());
  292. if (is_visible_in_tree())
  293. c->cast_to<ScriptEditorBase>()->ensure_focus();
  294. }
  295. if (c->cast_to<EditorHelp>()) {
  296. script_name_label->set_text(c->cast_to<EditorHelp>()->get_class());
  297. script_icon->set_texture(get_icon("Help","EditorIcons"));
  298. if (is_visible_in_tree())
  299. c->cast_to<EditorHelp>()->set_focused();
  300. }
  301. c->set_meta("__editor_pass",++edit_pass);
  302. _update_history_arrows();
  303. _update_script_colors();
  304. _update_selected_editor_menu();
  305. }
  306. void ScriptEditor::_close_tab(int p_idx, bool p_save) {
  307. int selected = p_idx;
  308. if (selected<0 || selected>=tab_container->get_child_count())
  309. return;
  310. Node *tselected = tab_container->get_child(selected);
  311. ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
  312. if (current) {
  313. if (p_save) {
  314. apply_scripts();
  315. }
  316. if (current->get_edit_menu()) {
  317. memdelete(current->get_edit_menu());
  318. }
  319. }
  320. //remove from history
  321. history.resize(history_pos+1);
  322. for(int i=0;i<history.size();i++) {
  323. if (history[i].control==tselected) {
  324. history.remove(i);
  325. i--;
  326. history_pos--;
  327. }
  328. }
  329. if (history_pos>=history.size()) {
  330. history_pos=history.size()-1;
  331. }
  332. int idx = tab_container->get_current_tab();
  333. memdelete(tselected);
  334. if (idx>=tab_container->get_child_count())
  335. idx=tab_container->get_child_count()-1;
  336. if (idx>=0) {
  337. if (history_pos>=0) {
  338. idx = history[history_pos].control->get_index();
  339. }
  340. tab_container->set_current_tab(idx);
  341. //script_list->select(idx);
  342. }
  343. _update_history_arrows();
  344. _update_script_names();
  345. _save_layout();
  346. }
  347. void ScriptEditor::_close_current_tab() {
  348. _close_tab(tab_container->get_current_tab());
  349. }
  350. void ScriptEditor::_close_discard_current_tab(const String& p_str) {
  351. _close_tab(tab_container->get_current_tab(), false);
  352. erase_tab_confirm->hide();
  353. }
  354. void ScriptEditor::_close_docs_tab() {
  355. int child_count = tab_container->get_child_count();
  356. for (int i = child_count-1; i>=0; i--) {
  357. EditorHelp *se = tab_container->get_child(i)->cast_to<EditorHelp>();
  358. if (se) {
  359. _close_tab(i);
  360. }
  361. }
  362. }
  363. void ScriptEditor::_close_all_tabs() {
  364. int child_count = tab_container->get_child_count();
  365. for (int i = child_count-1; i>=0; i--) {
  366. tab_container->set_current_tab(i);
  367. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  368. if (se) {
  369. // Maybe there are unsaved changes
  370. if (se->is_unsaved()) {
  371. _ask_close_current_unsaved_tab(se);
  372. continue;
  373. }
  374. }
  375. _close_current_tab();
  376. }
  377. }
  378. void ScriptEditor::_ask_close_current_unsaved_tab(ScriptEditorBase *current) {
  379. erase_tab_confirm->set_text("Close and save changes?\n\""+current->get_name()+"\"");
  380. erase_tab_confirm->popup_centered_minsize();
  381. }
  382. void ScriptEditor::_resave_scripts(const String& p_str) {
  383. apply_scripts();
  384. for(int i=0;i<tab_container->get_child_count();i++) {
  385. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  386. if (!se)
  387. continue;
  388. Ref<Script> script = se->get_edited_script();
  389. if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1)
  390. continue; //internal script, who cares
  391. if (trim_trailing_whitespace_on_save) {
  392. se->trim_trailing_whitespace();
  393. }
  394. editor->save_resource(script);
  395. se->tag_saved_version();
  396. }
  397. disk_changed->hide();
  398. }
  399. void ScriptEditor::_reload_scripts(){
  400. for(int i=0;i<tab_container->get_child_count();i++) {
  401. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  402. if (!se) {
  403. continue;
  404. }
  405. Ref<Script> script = se->get_edited_script();
  406. if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) {
  407. continue; //internal script, who cares
  408. }
  409. uint64_t last_date = script->get_last_modified_time();
  410. uint64_t date = FileAccess::get_modified_time(script->get_path());
  411. //printf("last date: %lli vs date: %lli\n",last_date,date);
  412. if (last_date==date) {
  413. continue;
  414. }
  415. Ref<Script> rel_script = ResourceLoader::load(script->get_path(),script->get_class(),true);
  416. ERR_CONTINUE(!rel_script.is_valid());
  417. script->set_source_code( rel_script->get_source_code() );
  418. script->set_last_modified_time( rel_script->get_last_modified_time() );
  419. script->reload();
  420. se->reload_text();
  421. }
  422. disk_changed->hide();
  423. _update_script_names();
  424. }
  425. void ScriptEditor::_res_saved_callback(const Ref<Resource>& p_res) {
  426. for(int i=0;i<tab_container->get_child_count();i++) {
  427. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  428. if (!se) {
  429. continue;
  430. }
  431. Ref<Script> script = se->get_edited_script();
  432. if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1) {
  433. continue; //internal script, who cares
  434. }
  435. if (script==p_res) {
  436. se->tag_saved_version();
  437. }
  438. }
  439. _update_script_names();
  440. if (!pending_auto_reload && auto_reload_running_scripts) {
  441. call_deferred("_live_auto_reload_running_scripts");
  442. pending_auto_reload=true;
  443. }
  444. }
  445. void ScriptEditor::_live_auto_reload_running_scripts() {
  446. pending_auto_reload=false;
  447. debugger->reload_scripts();
  448. }
  449. bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) {
  450. disk_changed_list->clear();
  451. TreeItem *r = disk_changed_list->create_item();
  452. disk_changed_list->set_hide_root(true);
  453. bool need_ask=false;
  454. bool need_reload=false;
  455. bool use_autoreload=bool(EDITOR_DEF("text_editor/files/auto_reload_scripts_on_external_change",false));
  456. for(int i=0;i<tab_container->get_child_count();i++) {
  457. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  458. if (se) {
  459. Ref<Script> script = se->get_edited_script();
  460. if (p_for_script.is_valid() && p_for_script!=script)
  461. continue;
  462. if (script->get_path()=="" || script->get_path().find("local://")!=-1 || script->get_path().find("::")!=-1)
  463. continue; //internal script, who cares
  464. uint64_t last_date = script->get_last_modified_time();
  465. uint64_t date = FileAccess::get_modified_time(script->get_path());
  466. //printf("last date: %lli vs date: %lli\n",last_date,date);
  467. if (last_date!=date) {
  468. TreeItem *ti = disk_changed_list->create_item(r);
  469. ti->set_text(0,script->get_path().get_file());
  470. if (!use_autoreload || se->is_unsaved()) {
  471. need_ask=true;
  472. }
  473. need_reload=true;
  474. //r->set_metadata(0,);
  475. }
  476. }
  477. }
  478. if (need_reload) {
  479. if (!need_ask) {
  480. script_editor->_reload_scripts();
  481. need_reload=false;
  482. } else {
  483. disk_changed->call_deferred("popup_centered_ratio",0.5);
  484. }
  485. }
  486. return need_reload;
  487. }
  488. void ScriptEditor::_file_dialog_action(String p_file) {
  489. switch (file_dialog_option) {
  490. case FILE_SAVE_THEME_AS: {
  491. if(!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) {
  492. editor->show_warning(TTR("Error while saving theme"), TTR("Error saving"));
  493. }
  494. } break;
  495. case FILE_IMPORT_THEME: {
  496. if(!EditorSettings::get_singleton()->import_text_editor_theme(p_file)) {
  497. editor->show_warning(TTR("Error importing theme"), TTR("Error importing"));
  498. }
  499. } break;
  500. }
  501. file_dialog_option = -1;
  502. }
  503. void ScriptEditor::_menu_option(int p_option) {
  504. switch(p_option) {
  505. case FILE_NEW: {
  506. script_create_dialog->config("Node", ".gd");
  507. script_create_dialog->popup_centered(Size2(300, 300)*EDSCALE);
  508. } break;
  509. case FILE_OPEN: {
  510. editor->open_resource("Script");
  511. return;
  512. } break;
  513. case FILE_SAVE_ALL: {
  514. if (_test_script_times_on_disk())
  515. return;
  516. save_all_scripts();
  517. } break;
  518. case FILE_IMPORT_THEME: {
  519. file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
  520. file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  521. file_dialog_option = FILE_IMPORT_THEME;
  522. file_dialog->clear_filters();
  523. file_dialog->add_filter("*.tet");
  524. file_dialog->popup_centered_ratio();
  525. file_dialog->set_title(TTR("Import Theme"));
  526. } break;
  527. case FILE_RELOAD_THEME: {
  528. EditorSettings::get_singleton()->load_text_editor_theme();
  529. } break;
  530. case FILE_SAVE_THEME: {
  531. if(!EditorSettings::get_singleton()->save_text_editor_theme()) {
  532. editor->show_warning(TTR("Error while saving theme"), TTR("Error saving"));
  533. }
  534. } break;
  535. case FILE_SAVE_THEME_AS: {
  536. file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE);
  537. file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  538. file_dialog_option = FILE_SAVE_THEME_AS;
  539. file_dialog->clear_filters();
  540. file_dialog->add_filter("*.tet");
  541. file_dialog->set_current_path(EditorSettings::get_singleton()->get_settings_path() + "/text_editor_themes/" + EditorSettings::get_singleton()->get("text_editor/theme/color_theme"));
  542. file_dialog->popup_centered_ratio();
  543. file_dialog->set_title(TTR("Save Theme As.."));
  544. } break;
  545. case SEARCH_HELP: {
  546. help_search_dialog->popup();
  547. } break;
  548. case SEARCH_CLASSES: {
  549. String current;
  550. if (tab_container->get_tab_count()>0) {
  551. EditorHelp *eh = tab_container->get_child( tab_container->get_current_tab() )->cast_to<EditorHelp>();
  552. if (eh) {
  553. current=eh->get_class();
  554. }
  555. }
  556. help_index->popup();
  557. if (current!="") {
  558. help_index->call_deferred("select_class",current);
  559. }
  560. } break;
  561. case SEARCH_WEBSITE: {
  562. OS::get_singleton()->shell_open("http://docs.godotengine.org/");
  563. } break;
  564. case WINDOW_NEXT: {
  565. _history_forward();
  566. } break;
  567. case WINDOW_PREV: {
  568. _history_back();
  569. } break;
  570. case DEBUG_SHOW: {
  571. if (debugger) {
  572. bool visible = debug_menu->get_popup()->is_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW) );
  573. debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW), !visible);
  574. if (visible)
  575. debugger->hide();
  576. else
  577. debugger->show();
  578. }
  579. } break;
  580. case DEBUG_SHOW_KEEP_OPEN: {
  581. bool visible = debug_menu->get_popup()->is_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN) );
  582. if (debugger)
  583. debugger->set_hide_on_stop(visible);
  584. debug_menu->get_popup()->set_item_checked( debug_menu->get_popup()->get_item_index(DEBUG_SHOW_KEEP_OPEN), !visible);
  585. } break;
  586. }
  587. int selected = tab_container->get_current_tab();
  588. if (selected<0 || selected>=tab_container->get_child_count())
  589. return;
  590. ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
  591. if (current) {
  592. switch(p_option) {
  593. case FILE_NEW: {
  594. script_create_dialog->config("Node", ".gd");
  595. script_create_dialog->popup_centered(Size2(300, 300)*EDSCALE);
  596. } break;
  597. case FILE_SAVE: {
  598. if (_test_script_times_on_disk())
  599. return;
  600. if (trim_trailing_whitespace_on_save)
  601. current->trim_trailing_whitespace();
  602. editor->save_resource( current->get_edited_script() );
  603. } break;
  604. case FILE_SAVE_AS: {
  605. current->trim_trailing_whitespace();
  606. editor->push_item(current->get_edited_script()->cast_to<Object>());
  607. editor->save_resource_as( current->get_edited_script() );
  608. } break;
  609. case FILE_TOOL_RELOAD:
  610. case FILE_TOOL_RELOAD_SOFT: {
  611. current->reload(p_option==FILE_TOOL_RELOAD_SOFT);
  612. } break;
  613. case FILE_CLOSE: {
  614. if (current->is_unsaved()) {
  615. _ask_close_current_unsaved_tab(current);
  616. } else {
  617. _close_current_tab();
  618. }
  619. } break;
  620. case CLOSE_DOCS: {
  621. _close_docs_tab();
  622. } break;
  623. case CLOSE_ALL: {
  624. _close_all_tabs();
  625. } break;
  626. case DEBUG_NEXT: {
  627. if (debugger)
  628. debugger->debug_next();
  629. } break;
  630. case DEBUG_STEP: {
  631. if (debugger)
  632. debugger->debug_step();
  633. } break;
  634. case DEBUG_BREAK: {
  635. if (debugger)
  636. debugger->debug_break();
  637. } break;
  638. case DEBUG_CONTINUE: {
  639. if (debugger)
  640. debugger->debug_continue();
  641. } break;
  642. case WINDOW_MOVE_LEFT: {
  643. if (tab_container->get_current_tab()>0) {
  644. tab_container->call_deferred("set_current_tab",tab_container->get_current_tab()-1);
  645. script_list->call_deferred("select",tab_container->get_current_tab()-1);
  646. tab_container->move_child(current,tab_container->get_current_tab()-1);
  647. _update_script_names();
  648. }
  649. } break;
  650. case WINDOW_MOVE_RIGHT: {
  651. if (tab_container->get_current_tab()<tab_container->get_child_count()-1) {
  652. tab_container->call_deferred("set_current_tab",tab_container->get_current_tab()+1);
  653. script_list->call_deferred("select",tab_container->get_current_tab()+1);
  654. tab_container->move_child(current,tab_container->get_current_tab()+1);
  655. _update_script_names();
  656. }
  657. } break;
  658. default: {
  659. if (p_option>=WINDOW_SELECT_BASE) {
  660. tab_container->set_current_tab(p_option-WINDOW_SELECT_BASE);
  661. script_list->select(p_option-WINDOW_SELECT_BASE);
  662. }
  663. }
  664. }
  665. }
  666. EditorHelp *help = tab_container->get_current_tab_control()->cast_to<EditorHelp>();
  667. if (help) {
  668. switch(p_option) {
  669. case HELP_SEARCH_FIND: {
  670. help->popup_search();
  671. } break;
  672. case HELP_SEARCH_FIND_NEXT: {
  673. help->search_again();
  674. } break;
  675. case FILE_CLOSE: {
  676. _close_current_tab();
  677. } break;
  678. case CLOSE_DOCS: {
  679. _close_docs_tab();
  680. } break;
  681. case CLOSE_ALL: {
  682. _close_all_tabs();
  683. } break;
  684. }
  685. }
  686. }
  687. void ScriptEditor::_tab_changed(int p_which) {
  688. ensure_select_current();
  689. }
  690. void ScriptEditor::_notification(int p_what) {
  691. if (p_what==NOTIFICATION_ENTER_TREE) {
  692. editor->connect("play_pressed",this,"_editor_play");
  693. editor->connect("pause_pressed",this,"_editor_pause");
  694. editor->connect("stop_pressed",this,"_editor_stop");
  695. editor->connect("script_add_function_request",this,"_add_callback");
  696. editor->connect("resource_saved",this,"_res_saved_callback");
  697. script_list->connect("item_selected",this,"_script_selected");
  698. script_split->connect("dragged",this,"_script_split_dragged");
  699. autosave_timer->connect("timeout",this,"_autosave_scripts");
  700. {
  701. float autosave_time = EditorSettings::get_singleton()->get("text_editor/files/autosave_interval_secs");
  702. if (autosave_time>0) {
  703. autosave_timer->set_wait_time(autosave_time);
  704. autosave_timer->start();
  705. } else {
  706. autosave_timer->stop();
  707. }
  708. }
  709. EditorSettings::get_singleton()->connect("settings_changed",this,"_editor_settings_changed");
  710. help_search->set_icon(get_icon("Help","EditorIcons"));
  711. site_search->set_icon(get_icon("Godot","EditorIcons"));
  712. class_search->set_icon(get_icon("ClassList","EditorIcons"));
  713. script_forward->set_icon(get_icon("Forward","EditorIcons"));
  714. script_back->set_icon(get_icon("Back","EditorIcons"));
  715. }
  716. if (p_what==NOTIFICATION_READY) {
  717. get_tree()->connect("tree_changed",this,"_tree_changed");
  718. editor->connect("request_help",this,"_request_help");
  719. }
  720. if (p_what==NOTIFICATION_EXIT_TREE) {
  721. editor->disconnect("play_pressed",this,"_editor_play");
  722. editor->disconnect("pause_pressed",this,"_editor_pause");
  723. editor->disconnect("stop_pressed",this,"_editor_stop");
  724. }
  725. if (p_what==MainLoop::NOTIFICATION_WM_FOCUS_IN) {
  726. _test_script_times_on_disk();
  727. _update_modified_scripts_for_external_editor();
  728. }
  729. if (p_what==NOTIFICATION_PROCESS) {
  730. }
  731. }
  732. bool ScriptEditor::can_take_away_focus() const {
  733. int selected = tab_container->get_current_tab();
  734. if (selected<0 || selected>=tab_container->get_child_count())
  735. return true;
  736. ScriptEditorBase *current = tab_container->get_child(selected)->cast_to<ScriptEditorBase>();
  737. if (!current)
  738. return true;
  739. return current->can_lose_focus_on_node_selection();
  740. }
  741. void ScriptEditor::close_builtin_scripts_from_scene(const String& p_scene) {
  742. for(int i=0;i<tab_container->get_child_count();i++) {
  743. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  744. if (se) {
  745. Ref<Script> script = se->get_edited_script();
  746. if (!script.is_valid())
  747. continue;
  748. if (script->get_path().find("::")!=-1 && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed
  749. _close_tab(i);
  750. i--;
  751. }
  752. }
  753. }
  754. }
  755. void ScriptEditor::edited_scene_changed() {
  756. _update_modified_scripts_for_external_editor();
  757. }
  758. static const Node * _find_node_with_script(const Node* p_node, const RefPtr & p_script) {
  759. if (p_node->get_script()==p_script)
  760. return p_node;
  761. for(int i=0;i<p_node->get_child_count();i++) {
  762. const Node *result = _find_node_with_script(p_node->get_child(i),p_script);
  763. if (result)
  764. return result;
  765. }
  766. return NULL;
  767. }
  768. Dictionary ScriptEditor::get_state() const {
  769. //apply_scripts();
  770. Dictionary state;
  771. #if 0
  772. Array paths;
  773. int open=-1;
  774. for(int i=0;i<tab_container->get_child_count();i++) {
  775. ScriptTextEditor *se = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
  776. if (!se)
  777. continue;
  778. Ref<Script> script = se->get_edited_script();
  779. if (script->get_path()!="" && script->get_path().find("local://")==-1 && script->get_path().find("::")==-1) {
  780. paths.push_back(script->get_path());
  781. } else {
  782. const Node *owner = _find_node_with_script(get_tree()->get_root(),script.get_ref_ptr());
  783. if (owner)
  784. paths.push_back(owner->get_path());
  785. }
  786. if (i==tab_container->get_current_tab())
  787. open=i;
  788. }
  789. if (paths.size())
  790. state["sources"]=paths;
  791. if (open!=-1)
  792. state["current"]=open;
  793. #endif
  794. return state;
  795. }
  796. void ScriptEditor::set_state(const Dictionary& p_state) {
  797. #if 0
  798. print_line("attempt set state: "+String(Variant(p_state)));
  799. if (!p_state.has("sources"))
  800. return; //bleh
  801. Array sources = p_state["sources"];
  802. for(int i=0;i<sources.size();i++) {
  803. Variant source=sources[i];
  804. Ref<Script> script;
  805. if (source.get_type()==Variant::NODE_PATH) {
  806. Node *owner=get_tree()->get_root()->get_node(source);
  807. if (!owner)
  808. continue;
  809. script = owner->get_script();
  810. } else if (source.get_type()==Variant::STRING) {
  811. script = ResourceLoader::load(source,"Script");
  812. }
  813. if (script.is_null()) //ah well..
  814. continue;
  815. editor->call("_resource_selected",script);
  816. }
  817. if (p_state.has("current")) {
  818. tab_container->set_current_tab(p_state["current"]);
  819. }
  820. #endif
  821. }
  822. void ScriptEditor::clear() {
  823. #if 0
  824. List<ScriptTextEditor*> stes;
  825. for(int i=0;i<tab_container->get_child_count();i++) {
  826. ScriptTextEditor *se = tab_container->get_child(i)->cast_to<ScriptTextEditor>();
  827. if (!se)
  828. continue;
  829. stes.push_back(se);
  830. }
  831. while(stes.size()) {
  832. memdelete(stes.front()->get());
  833. stes.pop_front();
  834. }
  835. int idx = tab_container->get_current_tab();
  836. if (idx>=tab_container->get_child_count())
  837. idx=tab_container->get_child_count()-1;
  838. if (idx>=0) {
  839. tab_container->set_current_tab(idx);
  840. script_list->select( script_list->find_metadata(idx) );
  841. }
  842. #endif
  843. }
  844. void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) {
  845. for(int i=0;i<tab_container->get_child_count();i++) {
  846. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  847. if (!se)
  848. continue;
  849. List<int> bpoints;
  850. se->get_breakpoints(&bpoints);
  851. Ref<Script> script = se->get_edited_script();
  852. String base = script->get_path();
  853. ERR_CONTINUE( base.begins_with("local://") || base=="" );
  854. for(List<int>::Element *E=bpoints.front();E;E=E->next()) {
  855. p_breakpoints->push_back(base+":"+itos(E->get()+1));
  856. }
  857. }
  858. }
  859. void ScriptEditor::ensure_focus_current() {
  860. if (!is_inside_tree())
  861. return;
  862. int cidx = tab_container->get_current_tab();
  863. if (cidx<0 || cidx>=tab_container->get_tab_count());
  864. Control *c = tab_container->get_child(cidx)->cast_to<Control>();
  865. if (!c)
  866. return;
  867. ScriptEditorBase *se = c->cast_to<ScriptEditorBase>();
  868. if (!se)
  869. return;
  870. se->ensure_focus();
  871. }
  872. void ScriptEditor::_script_selected(int p_idx) {
  873. grab_focus_block = !Input::get_singleton()->is_mouse_button_pressed(1); //amazing hack, simply amazing
  874. _go_to_tab(script_list->get_item_metadata(p_idx));
  875. grab_focus_block=false;
  876. }
  877. void ScriptEditor::ensure_select_current() {
  878. if (tab_container->get_child_count() && tab_container->get_current_tab()>=0) {
  879. Node *current = tab_container->get_child(tab_container->get_current_tab());
  880. ScriptEditorBase *se = current->cast_to<ScriptEditorBase>();
  881. if (se) {
  882. Ref<Script> script = se->get_edited_script();
  883. if (!grab_focus_block && is_visible_in_tree())
  884. se->ensure_focus();
  885. //edit_menu->show();
  886. //search_menu->show();
  887. }
  888. EditorHelp *eh = current->cast_to<EditorHelp>();
  889. if (eh) {
  890. //edit_menu->hide();
  891. //search_menu->hide();
  892. //script_search_menu->show();
  893. }
  894. }
  895. _update_selected_editor_menu();
  896. }
  897. void ScriptEditor::_find_scripts(Node* p_base, Node* p_current, Set<Ref<Script> > &used) {
  898. if (p_current!=p_base && p_current->get_owner()!=p_base)
  899. return;
  900. if (p_current->get_script_instance()) {
  901. Ref<Script> scr = p_current->get_script();
  902. if (scr.is_valid())
  903. used.insert(scr);
  904. }
  905. for(int i=0;i<p_current->get_child_count();i++) {
  906. _find_scripts(p_base,p_current->get_child(i),used);
  907. }
  908. }
  909. struct _ScriptEditorItemData {
  910. String name;
  911. Ref<Texture> icon;
  912. int index;
  913. String tooltip;
  914. bool used;
  915. int category;
  916. bool operator<(const _ScriptEditorItemData& id) const {
  917. return category==id.category?name.nocasecmp_to(id.name)<0:category<id.category;
  918. }
  919. };
  920. void ScriptEditor::_update_script_colors() {
  921. bool script_temperature_enabled = EditorSettings::get_singleton()->get("text_editor/open_scripts/script_temperature_enabled");
  922. bool highlight_current = EditorSettings::get_singleton()->get("text_editor/open_scripts/highlight_current_script");
  923. int hist_size = EditorSettings::get_singleton()->get("text_editor/open_scripts/script_temperature_history_size");
  924. Color hot_color=EditorSettings::get_singleton()->get("text_editor/open_scripts/script_temperature_hot_color");
  925. Color cold_color=EditorSettings::get_singleton()->get("text_editor/open_scripts/script_temperature_cold_color");
  926. for(int i=0;i<script_list->get_item_count();i++) {
  927. int c = script_list->get_item_metadata(i);
  928. Node *n = tab_container->get_child(c);
  929. if (!n)
  930. continue;
  931. script_list->set_item_custom_bg_color(i,Color(0,0,0,0));
  932. bool current = tab_container->get_current_tab() == c;
  933. if (current && highlight_current) {
  934. script_list->set_item_custom_bg_color(i, EditorSettings::get_singleton()->get("text_editor/open_scripts/current_script_background_color"));
  935. } else if (script_temperature_enabled) {
  936. if (!n->has_meta("__editor_pass")) {
  937. continue;
  938. }
  939. int pass=n->get_meta("__editor_pass");
  940. int h = edit_pass - pass;
  941. if (h>hist_size) {
  942. continue;
  943. }
  944. int non_zero_hist_size = ( hist_size == 0 ) ? 1 : hist_size;
  945. float v = Math::ease((edit_pass-pass)/float(non_zero_hist_size),0.4);
  946. script_list->set_item_custom_bg_color(i,hot_color.linear_interpolate(cold_color,v));
  947. }
  948. }
  949. }
  950. void ScriptEditor::_update_script_names() {
  951. if (restoring_layout)
  952. return;
  953. waiting_update_names=false;
  954. Set<Ref<Script> > used;
  955. Node* edited = EditorNode::get_singleton()->get_edited_scene();
  956. if (edited) {
  957. _find_scripts(edited,edited,used);
  958. }
  959. script_list->clear();
  960. bool split_script_help = EditorSettings::get_singleton()->get("text_editor/open_scripts/group_help_pages");
  961. Vector<_ScriptEditorItemData> sedata;
  962. for(int i=0;i<tab_container->get_child_count();i++) {
  963. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  964. if (se) {
  965. String name = se->get_name();
  966. Ref<Texture> icon = se->get_icon();
  967. String tooltip = se->get_edited_script()->get_path();
  968. _ScriptEditorItemData sd;
  969. sd.icon=icon;
  970. sd.name=name;
  971. sd.tooltip=tooltip;
  972. sd.index=i;
  973. sd.used=used.has(se->get_edited_script());
  974. sd.category=0;
  975. sedata.push_back(sd);
  976. }
  977. EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
  978. if (eh) {
  979. String name = eh->get_class();
  980. Ref<Texture> icon = get_icon("Help","EditorIcons");
  981. String tooltip = name+" Class Reference";
  982. _ScriptEditorItemData sd;
  983. sd.icon=icon;
  984. sd.name=name;
  985. sd.tooltip=tooltip;
  986. sd.index=i;
  987. sd.used=false;
  988. sd.category=split_script_help?1:0;
  989. sedata.push_back(sd);
  990. }
  991. }
  992. sedata.sort();
  993. for(int i=0;i<sedata.size();i++) {
  994. script_list->add_item(sedata[i].name,sedata[i].icon);
  995. int index = script_list->get_item_count()-1;
  996. script_list->set_item_tooltip(index,sedata[i].tooltip);
  997. script_list->set_item_metadata(index,sedata[i].index);
  998. if (sedata[i].used) {
  999. script_list->set_item_custom_bg_color(index,Color(88/255.0,88/255.0,60/255.0));
  1000. }
  1001. if (tab_container->get_current_tab()==sedata[i].index) {
  1002. script_list->select(index);
  1003. script_name_label->set_text(sedata[i].name);
  1004. script_icon->set_texture(sedata[i].icon);
  1005. }
  1006. }
  1007. _update_script_colors();
  1008. }
  1009. void ScriptEditor::edit(const Ref<Script>& p_script, bool p_grab_focus) {
  1010. if (p_script.is_null())
  1011. return;
  1012. // refuse to open built-in if scene is not loaded
  1013. // see if already has it
  1014. bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change");
  1015. if (p_script->get_path().is_resource_file() && bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) {
  1016. String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path");
  1017. String flags = EditorSettings::get_singleton()->get("text_editor/external/exec_flags");
  1018. List<String> args;
  1019. flags=flags.strip_edges();
  1020. if (flags!=String()) {
  1021. Vector<String> flagss = flags.split(" ",false);
  1022. for(int i=0;i<flagss.size();i++)
  1023. args.push_back(flagss[i]);
  1024. }
  1025. args.push_back(GlobalConfig::get_singleton()->globalize_path(p_script->get_path()));
  1026. Error err = OS::get_singleton()->execute(path,args,false);
  1027. if (err==OK)
  1028. return;
  1029. WARN_PRINT("Couldn't open external text editor, using internal");
  1030. }
  1031. for(int i=0;i<tab_container->get_child_count();i++) {
  1032. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1033. if (!se)
  1034. continue;
  1035. if (se->get_edited_script()==p_script) {
  1036. if (open_dominant || !EditorNode::get_singleton()->is_changing_scene()) {
  1037. if (tab_container->get_current_tab()!=i) {
  1038. _go_to_tab(i);
  1039. script_list->select( script_list->find_metadata(i) );
  1040. }
  1041. if (is_visible_in_tree())
  1042. se->ensure_focus();
  1043. }
  1044. return;
  1045. }
  1046. }
  1047. // doesn't have it, make a new one
  1048. ScriptEditorBase *se;
  1049. for(int i=script_editor_func_count-1;i>=0;i--) {
  1050. se = script_editor_funcs[i](p_script);
  1051. if (se)
  1052. break;
  1053. }
  1054. ERR_FAIL_COND(!se);
  1055. tab_container->add_child(se);
  1056. se->set_edited_script(p_script);
  1057. se->set_tooltip_request_func("_get_debug_tooltip",this);
  1058. if (se->get_edit_menu()) {
  1059. se->get_edit_menu()->hide();
  1060. menu_hb->add_child(se->get_edit_menu());
  1061. menu_hb->move_child(se->get_edit_menu(),1);
  1062. }
  1063. if (p_grab_focus) {
  1064. _go_to_tab(tab_container->get_tab_count()-1);
  1065. }
  1066. _update_script_names();
  1067. _save_layout();
  1068. se->connect("name_changed",this,"_update_script_names");
  1069. se->connect("request_help_search",this,"_help_search");
  1070. se->connect("request_open_script_at_line",this,"_goto_script_line");
  1071. se->connect("go_to_help",this,"_help_class_goto");
  1072. se->connect("request_save_history",this,"_save_history");
  1073. //test for modification, maybe the script was not edited but was loaded
  1074. _test_script_times_on_disk(p_script);
  1075. _update_modified_scripts_for_external_editor(p_script);
  1076. }
  1077. void ScriptEditor::save_all_scripts() {
  1078. for(int i=0;i<tab_container->get_child_count();i++) {
  1079. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1080. if (!se)
  1081. continue;
  1082. if (!se->is_unsaved())
  1083. continue;
  1084. if (trim_trailing_whitespace_on_save) {
  1085. se->trim_trailing_whitespace();
  1086. }
  1087. Ref<Script> script = se->get_edited_script();
  1088. if (script.is_valid())
  1089. se->apply_code();
  1090. if (script->get_path()!="" && script->get_path().find("local://")==-1 &&script->get_path().find("::")==-1) {
  1091. //external script, save it
  1092. editor->save_resource(script);
  1093. //ResourceSaver::save(script->get_path(),script);
  1094. }
  1095. }
  1096. _update_script_names();
  1097. }
  1098. void ScriptEditor::apply_scripts() const {
  1099. for(int i=0;i<tab_container->get_child_count();i++) {
  1100. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1101. if (!se)
  1102. continue;
  1103. se->apply_code();
  1104. }
  1105. }
  1106. void ScriptEditor::_editor_play() {
  1107. debugger->start();
  1108. debug_menu->get_popup()->grab_focus();
  1109. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true );
  1110. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), true );
  1111. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), false );
  1112. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true );
  1113. //debugger_gui->start_listening(Globals::get_singleton()->get("debug/debug_port"));
  1114. }
  1115. void ScriptEditor::_editor_pause() {
  1116. }
  1117. void ScriptEditor::_editor_stop() {
  1118. debugger->stop();
  1119. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true );
  1120. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), true );
  1121. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), true );
  1122. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true );
  1123. for(int i=0;i<tab_container->get_child_count();i++) {
  1124. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1125. if (!se) {
  1126. continue;
  1127. }
  1128. se->set_debugger_active(false);
  1129. }
  1130. }
  1131. void ScriptEditor::_add_callback(Object *p_obj, const String& p_function, const PoolStringArray& p_args) {
  1132. //print_line("add callback! hohoho"); kinda sad to remove this
  1133. ERR_FAIL_COND(!p_obj);
  1134. Ref<Script> script = p_obj->get_script();
  1135. ERR_FAIL_COND( !script.is_valid() );
  1136. editor->push_item(script.ptr());
  1137. for(int i=0;i<tab_container->get_child_count();i++) {
  1138. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1139. if (!se)
  1140. continue;
  1141. if (se->get_edited_script()!=script)
  1142. continue;
  1143. se->add_callback(p_function,p_args);
  1144. _go_to_tab(i);
  1145. script_list->select( script_list->find_metadata(i) );
  1146. break;
  1147. }
  1148. }
  1149. void ScriptEditor::_save_layout() {
  1150. if (restoring_layout) {
  1151. return;
  1152. }
  1153. editor->save_layout();
  1154. }
  1155. void ScriptEditor::_editor_settings_changed() {
  1156. trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/files/trim_trailing_whitespace_on_save");
  1157. float autosave_time = EditorSettings::get_singleton()->get("text_editor/files/autosave_interval_secs");
  1158. if (autosave_time>0) {
  1159. autosave_timer->set_wait_time(autosave_time);
  1160. autosave_timer->start();
  1161. } else {
  1162. autosave_timer->stop();
  1163. }
  1164. if (current_theme == "") {
  1165. current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
  1166. } else if (current_theme != EditorSettings::get_singleton()->get("text_editor/theme/color_theme")) {
  1167. current_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
  1168. EditorSettings::get_singleton()->load_text_editor_theme();
  1169. }
  1170. for(int i=0;i<tab_container->get_child_count();i++) {
  1171. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1172. if (!se)
  1173. continue;
  1174. se->update_settings();
  1175. }
  1176. _update_script_colors();
  1177. ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/files/auto_reload_and_parse_scripts_on_save",true));
  1178. }
  1179. void ScriptEditor::_autosave_scripts() {
  1180. save_all_scripts();
  1181. }
  1182. void ScriptEditor::_tree_changed() {
  1183. if (waiting_update_names)
  1184. return;
  1185. waiting_update_names=true;
  1186. call_deferred("_update_script_names");
  1187. }
  1188. void ScriptEditor::_script_split_dragged(float) {
  1189. _save_layout();
  1190. }
  1191. void ScriptEditor::_unhandled_input(const InputEvent& p_event) {
  1192. if (p_event.key.pressed || !is_visible_in_tree()) return;
  1193. if (ED_IS_SHORTCUT("script_editor/next_script", p_event)) {
  1194. int next_tab = script_list->get_current() + 1;
  1195. next_tab %= script_list->get_item_count();
  1196. _go_to_tab(script_list->get_item_metadata(next_tab));
  1197. _update_script_names();
  1198. }
  1199. if (ED_IS_SHORTCUT("script_editor/prev_script", p_event)) {
  1200. int next_tab = script_list->get_current() - 1;
  1201. next_tab = next_tab >= 0 ? next_tab : script_list->get_item_count() - 1;
  1202. _go_to_tab(script_list->get_item_metadata(next_tab));
  1203. _update_script_names();
  1204. }
  1205. }
  1206. void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) {
  1207. if (!bool(EDITOR_DEF("text_editor/files/restore_scripts_on_load",true))) {
  1208. return;
  1209. }
  1210. if (!p_layout->has_section_key("ScriptEditor","open_scripts") && !p_layout->has_section_key("ScriptEditor","open_help"))
  1211. return;
  1212. Array scripts = p_layout->get_value("ScriptEditor","open_scripts");
  1213. Array helps;
  1214. if (p_layout->has_section_key("ScriptEditor","open_help"))
  1215. helps=p_layout->get_value("ScriptEditor","open_help");
  1216. restoring_layout=true;
  1217. for(int i=0;i<scripts.size();i++) {
  1218. String path = scripts[i];
  1219. if (!FileAccess::exists(path))
  1220. continue;
  1221. Ref<Script> scr = ResourceLoader::load(path);
  1222. if (scr.is_valid()) {
  1223. edit(scr);
  1224. }
  1225. }
  1226. for(int i=0;i<helps.size();i++) {
  1227. String path = helps[i];
  1228. _help_class_open(path);
  1229. }
  1230. for(int i=0;i<tab_container->get_child_count();i++) {
  1231. tab_container->get_child(i)->set_meta("__editor_pass",Variant());
  1232. }
  1233. if (p_layout->has_section_key("ScriptEditor","split_offset")) {
  1234. script_split->set_split_offset(p_layout->get_value("ScriptEditor","split_offset"));
  1235. }
  1236. restoring_layout=false;
  1237. _update_script_names();
  1238. }
  1239. void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) {
  1240. Array scripts;
  1241. Array helps;
  1242. for(int i=0;i<tab_container->get_child_count();i++) {
  1243. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1244. if (se) {
  1245. String path = se->get_edited_script()->get_path();
  1246. if (!path.is_resource_file())
  1247. continue;
  1248. scripts.push_back(path);
  1249. }
  1250. EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
  1251. if (eh) {
  1252. helps.push_back(eh->get_class());
  1253. }
  1254. }
  1255. p_layout->set_value("ScriptEditor","open_scripts",scripts);
  1256. p_layout->set_value("ScriptEditor","open_help",helps);
  1257. p_layout->set_value("ScriptEditor","split_offset",script_split->get_split_offset());
  1258. }
  1259. void ScriptEditor::_help_class_open(const String& p_class) {
  1260. if (p_class=="")
  1261. return;
  1262. for(int i=0;i<tab_container->get_child_count();i++) {
  1263. EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
  1264. if (eh && eh->get_class()==p_class) {
  1265. _go_to_tab(i);
  1266. _update_script_names();
  1267. return;
  1268. }
  1269. }
  1270. EditorHelp * eh = memnew( EditorHelp );
  1271. eh->set_name(p_class);
  1272. tab_container->add_child(eh);
  1273. _go_to_tab(tab_container->get_tab_count()-1);
  1274. eh->go_to_class(p_class,0);
  1275. eh->connect("go_to_help",this,"_help_class_goto");
  1276. _update_script_names();
  1277. _save_layout();
  1278. }
  1279. void ScriptEditor::_help_class_goto(const String& p_desc) {
  1280. String cname=p_desc.get_slice(":",1);
  1281. for(int i=0;i<tab_container->get_child_count();i++) {
  1282. EditorHelp *eh = tab_container->get_child(i)->cast_to<EditorHelp>();
  1283. if (eh && eh->get_class()==cname) {
  1284. _go_to_tab(i);
  1285. eh->go_to_help(p_desc);
  1286. _update_script_names();
  1287. return;
  1288. }
  1289. }
  1290. EditorHelp * eh = memnew( EditorHelp );
  1291. eh->set_name(cname);
  1292. tab_container->add_child(eh);
  1293. _go_to_tab(tab_container->get_tab_count()-1);
  1294. eh->go_to_help(p_desc);
  1295. eh->connect("go_to_help",this,"_help_class_goto");
  1296. _update_script_names();
  1297. _save_layout();
  1298. }
  1299. void ScriptEditor::_update_selected_editor_menu() {
  1300. for(int i=0;i<tab_container->get_child_count();i++) {
  1301. bool current = tab_container->get_current_tab() == i;
  1302. ScriptEditorBase *se = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1303. if (se && se->get_edit_menu()) {
  1304. if (current)
  1305. se->get_edit_menu()->show();
  1306. else
  1307. se->get_edit_menu()->hide();
  1308. }
  1309. }
  1310. EditorHelp *eh=tab_container->get_current_tab_control()->cast_to<EditorHelp>();
  1311. if (eh) {
  1312. script_search_menu->show();
  1313. } else {
  1314. script_search_menu->hide();
  1315. }
  1316. }
  1317. void ScriptEditor::_update_history_pos(int p_new_pos) {
  1318. Node *n = tab_container->get_current_tab_control();
  1319. if (n->cast_to<ScriptEditorBase>()) {
  1320. history[history_pos].state=n->cast_to<ScriptEditorBase>()->get_edit_state();
  1321. }
  1322. if (n->cast_to<EditorHelp>()) {
  1323. history[history_pos].state=n->cast_to<EditorHelp>()->get_scroll();
  1324. }
  1325. history_pos=p_new_pos;
  1326. tab_container->set_current_tab(history[history_pos].control->get_index());
  1327. n = history[history_pos].control;
  1328. if (n->cast_to<ScriptEditorBase>()) {
  1329. n->cast_to<ScriptEditorBase>()->set_edit_state(history[history_pos].state);
  1330. n->cast_to<ScriptEditorBase>()->ensure_focus();
  1331. }
  1332. if (n->cast_to<EditorHelp>()) {
  1333. n->cast_to<EditorHelp>()->set_scroll(history[history_pos].state);
  1334. n->cast_to<EditorHelp>()->set_focused();
  1335. }
  1336. n->set_meta("__editor_pass",++edit_pass);
  1337. _update_script_names();
  1338. _update_history_arrows();
  1339. _update_selected_editor_menu();
  1340. }
  1341. void ScriptEditor::_history_forward() {
  1342. if (history_pos<history.size()-1) {
  1343. _update_history_pos(history_pos+1);
  1344. }
  1345. }
  1346. void ScriptEditor::_history_back(){
  1347. if (history_pos>0) {
  1348. _update_history_pos(history_pos-1);
  1349. }
  1350. }
  1351. void ScriptEditor::set_scene_root_script( Ref<Script> p_script ) {
  1352. bool open_dominant = EditorSettings::get_singleton()->get("text_editor/files/open_dominant_script_on_scene_change");
  1353. if (bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor")))
  1354. return;
  1355. if (open_dominant && p_script.is_valid() && _can_open_in_editor(p_script.ptr())) {
  1356. edit(p_script);
  1357. }
  1358. }
  1359. bool ScriptEditor::script_go_to_method(Ref<Script> p_script, const String& p_method) {
  1360. for (int i=0;i<tab_container->get_child_count();i++) {
  1361. ScriptEditorBase *current = tab_container->get_child(i)->cast_to<ScriptEditorBase>();
  1362. if (current && current->get_edited_script()==p_script) {
  1363. if (current->goto_method(p_method)) {
  1364. edit(p_script);
  1365. return true;
  1366. }
  1367. break;
  1368. }
  1369. }
  1370. return false;
  1371. }
  1372. void ScriptEditor::set_live_auto_reload_running_scripts(bool p_enabled) {
  1373. auto_reload_running_scripts=p_enabled;
  1374. }
  1375. void ScriptEditor::_help_search(String p_text) {
  1376. help_search_dialog->popup(p_text);
  1377. }
  1378. void ScriptEditor::_open_script_request(const String& p_path) {
  1379. Ref<Script> script = ResourceLoader::load(p_path);
  1380. if (script.is_valid()) {
  1381. script_editor->edit(script,false);
  1382. }
  1383. }
  1384. int ScriptEditor::script_editor_func_count=0;
  1385. CreateScriptEditorFunc ScriptEditor::script_editor_funcs[ScriptEditor::SCRIPT_EDITOR_FUNC_MAX];
  1386. void ScriptEditor::register_create_script_editor_function(CreateScriptEditorFunc p_func) {
  1387. ERR_FAIL_COND(script_editor_func_count==SCRIPT_EDITOR_FUNC_MAX);
  1388. script_editor_funcs[script_editor_func_count++]=p_func;
  1389. }
  1390. void ScriptEditor::_bind_methods() {
  1391. ClassDB::bind_method("_file_dialog_action",&ScriptEditor::_file_dialog_action);
  1392. ClassDB::bind_method("_tab_changed",&ScriptEditor::_tab_changed);
  1393. ClassDB::bind_method("_menu_option",&ScriptEditor::_menu_option);
  1394. ClassDB::bind_method("_close_current_tab",&ScriptEditor::_close_current_tab);
  1395. ClassDB::bind_method("_close_discard_current_tab", &ScriptEditor::_close_discard_current_tab);
  1396. ClassDB::bind_method("_close_docs_tab", &ScriptEditor::_close_docs_tab);
  1397. ClassDB::bind_method("_close_all_tabs", &ScriptEditor::_close_all_tabs);
  1398. ClassDB::bind_method("_editor_play",&ScriptEditor::_editor_play);
  1399. ClassDB::bind_method("_editor_pause",&ScriptEditor::_editor_pause);
  1400. ClassDB::bind_method("_editor_stop",&ScriptEditor::_editor_stop);
  1401. ClassDB::bind_method("_add_callback",&ScriptEditor::_add_callback);
  1402. ClassDB::bind_method("_reload_scripts",&ScriptEditor::_reload_scripts);
  1403. ClassDB::bind_method("_resave_scripts",&ScriptEditor::_resave_scripts);
  1404. ClassDB::bind_method("_res_saved_callback",&ScriptEditor::_res_saved_callback);
  1405. ClassDB::bind_method("_goto_script_line",&ScriptEditor::_goto_script_line);
  1406. ClassDB::bind_method("_goto_script_line2",&ScriptEditor::_goto_script_line2);
  1407. ClassDB::bind_method("_help_search",&ScriptEditor::_help_search);
  1408. ClassDB::bind_method("_save_history",&ScriptEditor::_save_history);
  1409. ClassDB::bind_method("_breaked",&ScriptEditor::_breaked);
  1410. ClassDB::bind_method("_show_debugger",&ScriptEditor::_show_debugger);
  1411. ClassDB::bind_method("_get_debug_tooltip",&ScriptEditor::_get_debug_tooltip);
  1412. ClassDB::bind_method("_autosave_scripts",&ScriptEditor::_autosave_scripts);
  1413. ClassDB::bind_method("_editor_settings_changed",&ScriptEditor::_editor_settings_changed);
  1414. ClassDB::bind_method("_update_script_names",&ScriptEditor::_update_script_names);
  1415. ClassDB::bind_method("_tree_changed",&ScriptEditor::_tree_changed);
  1416. ClassDB::bind_method("_script_selected",&ScriptEditor::_script_selected);
  1417. ClassDB::bind_method("_script_created",&ScriptEditor::_script_created);
  1418. ClassDB::bind_method("_script_split_dragged",&ScriptEditor::_script_split_dragged);
  1419. ClassDB::bind_method("_help_class_open",&ScriptEditor::_help_class_open);
  1420. ClassDB::bind_method("_help_class_goto",&ScriptEditor::_help_class_goto);
  1421. ClassDB::bind_method("_request_help",&ScriptEditor::_help_class_open);
  1422. ClassDB::bind_method("_history_forward",&ScriptEditor::_history_forward);
  1423. ClassDB::bind_method("_history_back",&ScriptEditor::_history_back);
  1424. ClassDB::bind_method("_live_auto_reload_running_scripts",&ScriptEditor::_live_auto_reload_running_scripts);
  1425. ClassDB::bind_method("_unhandled_input",&ScriptEditor::_unhandled_input);
  1426. }
  1427. ScriptEditor::ScriptEditor(EditorNode *p_editor) {
  1428. current_theme = "";
  1429. completion_cache = memnew( EditorScriptCodeCompletionCache );
  1430. restoring_layout=false;
  1431. waiting_update_names=false;
  1432. pending_auto_reload=false;
  1433. auto_reload_running_scripts=false;
  1434. editor=p_editor;
  1435. menu_hb = memnew( HBoxContainer );
  1436. add_child(menu_hb);
  1437. script_split = memnew( HSplitContainer );
  1438. add_child(script_split);
  1439. script_split->set_v_size_flags(SIZE_EXPAND_FILL);
  1440. script_list = memnew( ItemList );
  1441. script_split->add_child(script_list);
  1442. script_list->set_custom_minimum_size(Size2(0,0));
  1443. script_split->set_split_offset(140);
  1444. tab_container = memnew( TabContainer );
  1445. tab_container->set_tabs_visible(false);
  1446. script_split->add_child(tab_container);
  1447. tab_container->set_h_size_flags(SIZE_EXPAND_FILL);
  1448. ED_SHORTCUT("script_editor/next_script", TTR("Next script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_GREATER);
  1449. ED_SHORTCUT("script_editor/prev_script", TTR("Previous script"), KEY_MASK_CMD | KEY_LESS);
  1450. set_process_unhandled_input(true);
  1451. file_menu = memnew( MenuButton );
  1452. menu_hb->add_child(file_menu);
  1453. file_menu->set_text(TTR("File"));
  1454. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New")), FILE_NEW);
  1455. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open")), FILE_OPEN);
  1456. file_menu->get_popup()->add_separator();
  1457. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save", TTR("Save"), KEY_MASK_ALT|KEY_MASK_CMD|KEY_S), FILE_SAVE);
  1458. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_as", TTR("Save As..")), FILE_SAVE_AS);
  1459. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_all", TTR("Save All"), KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_MASK_ALT|KEY_S), FILE_SAVE_ALL);
  1460. file_menu->get_popup()->add_separator();
  1461. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_script_soft", TTR("Soft Reload Script"), KEY_MASK_CMD|KEY_MASK_SHIFT|KEY_R), FILE_TOOL_RELOAD_SOFT);
  1462. file_menu->get_popup()->add_separator();
  1463. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_previous", TTR("History Prev"), KEY_MASK_ALT|KEY_LEFT), WINDOW_PREV);
  1464. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/history_next", TTR("History Next"), KEY_MASK_ALT|KEY_RIGHT), WINDOW_NEXT);
  1465. file_menu->get_popup()->add_separator();
  1466. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme")), FILE_IMPORT_THEME);
  1467. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), FILE_RELOAD_THEME);
  1468. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), FILE_SAVE_THEME);
  1469. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/save_theme_as", TTR("Save Theme As")), FILE_SAVE_THEME_AS);
  1470. file_menu->get_popup()->add_separator();
  1471. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS);
  1472. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE);
  1473. file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_all", TTR("Close All")), CLOSE_ALL);
  1474. file_menu->get_popup()->connect("id_pressed", this,"_menu_option");
  1475. script_search_menu = memnew( MenuButton );
  1476. menu_hb->add_child(script_search_menu);
  1477. script_search_menu->set_text(TTR("Search"));
  1478. script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find", TTR("Find.."), KEY_MASK_CMD|KEY_F), HELP_SEARCH_FIND);
  1479. script_search_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/find_next", TTR("Find Next"), KEY_F3), HELP_SEARCH_FIND_NEXT);
  1480. script_search_menu->get_popup()->connect("id_pressed", this,"_menu_option");
  1481. script_search_menu->hide();
  1482. debug_menu = memnew( MenuButton );
  1483. menu_hb->add_child(debug_menu);
  1484. debug_menu->set_text(TTR("Debug"));
  1485. debug_menu->get_popup()->add_separator();
  1486. debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_over", TTR("Step Over"), KEY_F10), DEBUG_NEXT);
  1487. debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/step_into", TTR("Step Into"), KEY_F11), DEBUG_STEP);
  1488. debug_menu->get_popup()->add_separator();
  1489. debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/break", TTR("Break")), DEBUG_BREAK);
  1490. debug_menu->get_popup()->add_shortcut(ED_SHORTCUT("debugger/continue", TTR("Continue")), DEBUG_CONTINUE);
  1491. debug_menu->get_popup()->add_separator();
  1492. //debug_menu->get_popup()->add_check_item("Show Debugger",DEBUG_SHOW);
  1493. debug_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("debugger/keep_debugger_open", TTR("Keep Debugger Open")), DEBUG_SHOW_KEEP_OPEN);
  1494. debug_menu->get_popup()->connect("id_pressed", this,"_menu_option");
  1495. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_NEXT), true);
  1496. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_STEP), true );
  1497. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_BREAK), true );
  1498. debug_menu->get_popup()->set_item_disabled( debug_menu->get_popup()->get_item_index(DEBUG_CONTINUE), true );
  1499. #if 0
  1500. window_menu = memnew( MenuButton );
  1501. menu_hb->add_child(window_menu);
  1502. window_menu->set_text(TTR("Window"));
  1503. window_menu->get_popup()->add_item(TTR("Close"),WINDOW_CLOSE,KEY_MASK_CMD|KEY_W);
  1504. window_menu->get_popup()->add_separator();
  1505. window_menu->get_popup()->add_item(TTR("Move Left"),WINDOW_MOVE_LEFT,KEY_MASK_CMD|KEY_LEFT);
  1506. window_menu->get_popup()->add_item(TTR("Move Right"),WINDOW_MOVE_RIGHT,KEY_MASK_CMD|KEY_RIGHT);
  1507. window_menu->get_popup()->add_separator();
  1508. window_menu->get_popup()->connect("id_pressed", this,"_menu_option");
  1509. #endif
  1510. menu_hb->add_spacer();
  1511. script_icon = memnew( TextureRect );
  1512. menu_hb->add_child(script_icon);
  1513. script_name_label = memnew( Label );
  1514. menu_hb->add_child(script_name_label);
  1515. script_icon->hide();
  1516. script_name_label->hide();
  1517. menu_hb->add_spacer();
  1518. site_search = memnew( ToolButton );
  1519. site_search->set_text(TTR("Tutorials"));
  1520. site_search->connect("pressed",this,"_menu_option",varray(SEARCH_WEBSITE));
  1521. menu_hb->add_child(site_search);
  1522. site_search->set_tooltip(TTR("Open https://godotengine.org at tutorials section."));
  1523. class_search = memnew( ToolButton );
  1524. class_search->set_text(TTR("Classes"));
  1525. class_search->connect("pressed",this,"_menu_option",varray(SEARCH_CLASSES));
  1526. menu_hb->add_child(class_search);
  1527. class_search->set_tooltip(TTR("Search the class hierarchy."));
  1528. help_search = memnew( ToolButton );
  1529. help_search->set_text(TTR("Search Help"));
  1530. help_search->connect("pressed",this,"_menu_option",varray(SEARCH_HELP));
  1531. menu_hb->add_child(help_search);
  1532. help_search->set_tooltip(TTR("Search the reference documentation."));
  1533. menu_hb->add_child( memnew( VSeparator) );
  1534. script_back = memnew( ToolButton );
  1535. script_back->connect("pressed",this,"_history_back");
  1536. menu_hb->add_child(script_back);
  1537. script_back->set_disabled(true);
  1538. script_back->set_tooltip(TTR("Go to previous edited document."));
  1539. script_forward = memnew( ToolButton );
  1540. script_forward->connect("pressed",this,"_history_forward");
  1541. menu_hb->add_child(script_forward);
  1542. script_forward->set_disabled(true);
  1543. script_forward->set_tooltip(TTR("Go to next edited document."));
  1544. tab_container->connect("tab_changed", this,"_tab_changed");
  1545. erase_tab_confirm = memnew( ConfirmationDialog );
  1546. erase_tab_confirm->get_ok()->set_text(TTR("Save"));
  1547. erase_tab_confirm->add_button(TTR("Discard"), OS::get_singleton()->get_swap_ok_cancel(), "discard");
  1548. erase_tab_confirm->connect("confirmed", this,"_close_current_tab");
  1549. erase_tab_confirm->connect("custom_action", this, "_close_discard_current_tab");
  1550. add_child(erase_tab_confirm);
  1551. script_create_dialog = memnew(ScriptCreateDialog);
  1552. script_create_dialog->set_title(TTR("Create Script"));
  1553. add_child(script_create_dialog);
  1554. script_create_dialog->connect("script_created", this, "_script_created");
  1555. file_dialog_option = -1;
  1556. file_dialog = memnew( EditorFileDialog );
  1557. add_child(file_dialog);
  1558. file_dialog->connect("file_selected", this,"_file_dialog_action");
  1559. debugger = memnew( ScriptEditorDebugger(editor) );
  1560. debugger->connect("goto_script_line",this,"_goto_script_line");
  1561. debugger->connect("show_debugger",this,"_show_debugger");
  1562. disk_changed = memnew( ConfirmationDialog );
  1563. {
  1564. VBoxContainer *vbc = memnew( VBoxContainer );
  1565. disk_changed->add_child(vbc);
  1566. //disk_changed->set_child_rect(vbc);
  1567. Label *dl = memnew( Label );
  1568. dl->set_text(TTR("The following files are newer on disk.\nWhat action should be taken?:"));
  1569. vbc->add_child(dl);
  1570. disk_changed_list = memnew( Tree );
  1571. vbc->add_child(disk_changed_list);
  1572. disk_changed_list->set_v_size_flags(SIZE_EXPAND_FILL);
  1573. disk_changed->connect("confirmed",this,"_reload_scripts");
  1574. disk_changed->get_ok()->set_text(TTR("Reload"));
  1575. disk_changed->add_button(TTR("Resave"),!OS::get_singleton()->get_swap_ok_cancel(),"resave");
  1576. disk_changed->connect("custom_action",this,"_resave_scripts");
  1577. }
  1578. add_child(disk_changed);
  1579. script_editor=this;
  1580. Button *db = EditorNode::get_singleton()->add_bottom_panel_item(TTR("Debugger"),debugger);
  1581. debugger->set_tool_button(db);
  1582. debugger->connect("breaked",this,"_breaked");
  1583. autosave_timer = memnew( Timer );
  1584. autosave_timer->set_one_shot(false);
  1585. add_child(autosave_timer);
  1586. grab_focus_block=false;
  1587. help_search_dialog = memnew( EditorHelpSearch );
  1588. add_child(help_search_dialog);
  1589. help_search_dialog->connect("go_to_help",this,"_help_class_goto");
  1590. help_index = memnew( EditorHelpIndex );
  1591. add_child(help_index);
  1592. help_index->connect("open_class",this,"_help_class_open");
  1593. history_pos=-1;
  1594. //debugger_gui->hide();
  1595. edit_pass=0;
  1596. trim_trailing_whitespace_on_save = false;
  1597. ScriptServer::edit_request_func=_open_script_request;
  1598. }
  1599. ScriptEditor::~ScriptEditor() {
  1600. memdelete(completion_cache);
  1601. }
  1602. void ScriptEditorPlugin::edit(Object *p_object) {
  1603. if (!p_object->cast_to<Script>())
  1604. return;
  1605. script_editor->edit(p_object->cast_to<Script>());
  1606. }
  1607. bool ScriptEditorPlugin::handles(Object *p_object) const {
  1608. if (p_object->cast_to<Script>()) {
  1609. bool valid = _can_open_in_editor(p_object->cast_to<Script>());
  1610. if (!valid) { //user tried to open it by clicking
  1611. EditorNode::get_singleton()->show_warning(TTR("Built-in scripts can only be edited when the scene they belong to is loaded"));
  1612. }
  1613. return valid;
  1614. }
  1615. return p_object->is_class("Script");
  1616. }
  1617. void ScriptEditorPlugin::make_visible(bool p_visible) {
  1618. if (p_visible) {
  1619. script_editor->show();
  1620. script_editor->set_process(true);
  1621. script_editor->ensure_select_current();
  1622. } else {
  1623. script_editor->hide();
  1624. script_editor->set_process(false);
  1625. }
  1626. }
  1627. void ScriptEditorPlugin::selected_notify() {
  1628. script_editor->ensure_select_current();
  1629. }
  1630. Dictionary ScriptEditorPlugin::get_state() const {
  1631. return script_editor->get_state();
  1632. }
  1633. void ScriptEditorPlugin::set_state(const Dictionary& p_state) {
  1634. script_editor->set_state(p_state);
  1635. }
  1636. void ScriptEditorPlugin::clear() {
  1637. script_editor->clear();
  1638. }
  1639. void ScriptEditorPlugin::save_external_data() {
  1640. script_editor->save_all_scripts();
  1641. }
  1642. void ScriptEditorPlugin::apply_changes() {
  1643. script_editor->apply_scripts();
  1644. }
  1645. void ScriptEditorPlugin::restore_global_state() {
  1646. }
  1647. void ScriptEditorPlugin::save_global_state() {
  1648. }
  1649. void ScriptEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
  1650. script_editor->set_window_layout(p_layout);
  1651. }
  1652. void ScriptEditorPlugin::get_window_layout(Ref<ConfigFile> p_layout){
  1653. script_editor->get_window_layout(p_layout);
  1654. }
  1655. void ScriptEditorPlugin::get_breakpoints(List<String> *p_breakpoints) {
  1656. return script_editor->get_breakpoints(p_breakpoints);
  1657. }
  1658. void ScriptEditorPlugin::edited_scene_changed() {
  1659. script_editor->edited_scene_changed();
  1660. }
  1661. ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) {
  1662. editor=p_node;
  1663. script_editor = memnew( ScriptEditor(p_node) );
  1664. editor->get_viewport()->add_child(script_editor);
  1665. script_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1666. script_editor->hide();
  1667. EDITOR_DEF("text_editor/files/auto_reload_scripts_on_external_change",true);
  1668. ScriptServer::set_reload_scripts_on_save(EDITOR_DEF("text_editor/files/auto_reload_and_parse_scripts_on_save",true));
  1669. EDITOR_DEF("text_editor/files/open_dominant_script_on_scene_change",true);
  1670. EDITOR_DEF("text_editor/external/use_external_editor",false);
  1671. EDITOR_DEF("text_editor/external/exec_path","");
  1672. EDITOR_DEF("text_editor/open_scripts/script_temperature_enabled",true);
  1673. EDITOR_DEF("text_editor/open_scripts/highlight_current_script", true);
  1674. EDITOR_DEF("text_editor/open_scripts/script_temperature_history_size",15);
  1675. EDITOR_DEF("text_editor/open_scripts/script_temperature_hot_color",Color(1,0,0,0.3));
  1676. EDITOR_DEF("text_editor/open_scripts/script_temperature_cold_color",Color(0,0,1,0.3));
  1677. EDITOR_DEF("text_editor/open_scripts/current_script_background_color",Color(0.81,0.81,0.14,0.63));
  1678. EDITOR_DEF("text_editor/open_scripts/group_help_pages",true);
  1679. EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING,"text_editor/external/exec_path",PROPERTY_HINT_GLOBAL_FILE));
  1680. EDITOR_DEF("text_editor/external/exec_flags","");
  1681. }
  1682. ScriptEditorPlugin::~ScriptEditorPlugin()
  1683. {
  1684. }