project_export.cpp 67 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043
  1. /*************************************************************************/
  2. /* project_export.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "project_export.h"
  31. #include "globals.h"
  32. #include "os/dir_access.h"
  33. #include "os/file_access.h"
  34. #include "io/resource_loader.h"
  35. #include "io/resource_saver.h"
  36. #include "os/os.h"
  37. #include "scene/gui/box_container.h"
  38. #include "compressed_translation.h"
  39. #include "editor_data.h"
  40. #include "editor_node.h"
  41. #include "editor_settings.h"
  42. #include "io/image_loader.h"
  43. #include "io_plugins/editor_texture_import_plugin.h"
  44. #include "scene/gui/scroll_container.h"
  45. #include "scene/gui/tab_container.h"
  46. const char *ProjectExportDialog::da_string[ProjectExportDialog::ACTION_MAX] = {
  47. "",
  48. "Copy",
  49. "Bundle"
  50. };
  51. bool ProjectExportDialog::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory *p_dir) {
  52. TreeItem *item = tree->create_item(p_parent);
  53. item->set_text(0, p_dir->get_name() + "/");
  54. item->set_icon(0, get_icon("Folder", "EditorIcons"));
  55. bool has_items = false;
  56. for (int i = 0; i < p_dir->get_subdir_count(); i++) {
  57. if (_create_tree(item, p_dir->get_subdir(i)))
  58. has_items = true;
  59. }
  60. // int cc = p_options.get_slice_count(",");
  61. for (int i = 0; i < p_dir->get_file_count(); i++) {
  62. TreeItem *fitem = tree->create_item(item);
  63. //fitem->set_cell_mode(0,TreeItem::CELL_MODE_CHECK);
  64. //fitem->set_editable(0,true);
  65. // fitem->set_checked(0,isfave);
  66. fitem->set_text(0, p_dir->get_file(i));
  67. String path = p_dir->get_file_path(i);
  68. fitem->set_tooltip(0, path);
  69. fitem->set_metadata(0, path);
  70. Ref<Texture> icon = get_icon((has_icon(p_dir->get_file_type(i), ei) ? p_dir->get_file_type(i) : ot), ei);
  71. fitem->set_icon(0, icon);
  72. fitem->set_cell_mode(1, TreeItem::CELL_MODE_RANGE);
  73. fitem->set_range_config(1, 0, 2, 1);
  74. fitem->set_text(1, expopt);
  75. fitem->set_editable(1, true);
  76. EditorImportExport::FileAction fa = EditorImportExport::get_singleton()->get_export_file_action(path);
  77. fitem->set_range(1, fa);
  78. has_items = true;
  79. }
  80. if (!has_items) {
  81. memdelete(item);
  82. return false;
  83. }
  84. return true;
  85. }
  86. void ProjectExportDialog::_tree_changed() {
  87. TreeItem *t = tree->get_selected();
  88. if (!t)
  89. return;
  90. String selected = t->get_metadata(0);
  91. EditorImportExport::get_singleton()->set_export_file_action(selected, EditorImportExport::FileAction(int(t->get_range(1))));
  92. _save_export_cfg();
  93. //editor->save_import_export(true);
  94. //EditorImportDB::get_singleton()->save_settings();
  95. }
  96. void ProjectExportDialog::popup_export() {
  97. popup_centered_ratio();
  98. if (pending_update_tree) {
  99. _update_tree();
  100. _update_group_tree();
  101. pending_update_tree = false;
  102. }
  103. }
  104. void ProjectExportDialog::_update_tree() {
  105. updating_tree = true;
  106. tree->clear();
  107. EditorFileSystemDirectory *efsd = EditorFileSystem::get_singleton()->get_filesystem();
  108. if (efsd) {
  109. _create_tree(NULL, efsd);
  110. }
  111. updating_tree = false;
  112. }
  113. void ProjectExportDialog::_update_platform() {
  114. _validate_platform();
  115. TreeItem *selected = platforms->get_selected();
  116. if (!selected)
  117. return;
  118. String platform = selected->get_metadata(0);
  119. Ref<EditorExportPlatform> exporter = EditorImportExport::get_singleton()->get_export_platform(platform);
  120. platform_options->edit(exporter.ptr());
  121. }
  122. void ProjectExportDialog::_platform_selected() {
  123. String p = platforms->get_selected()->get_metadata(0);
  124. _update_platform();
  125. // editor->save_import_export();
  126. // EditorFileSystem::get_singleton()->scan();
  127. }
  128. void ProjectExportDialog::_scan_finished() {
  129. /* print_line("**********SCAN DONEEE********");
  130. print_line("**********SCAN DONEEE********");
  131. print_line("**********SCAN DONEEE********");
  132. print_line("**********SCAN DONEEE********");*/
  133. if (!is_visible()) {
  134. pending_update_tree = true;
  135. return;
  136. }
  137. _update_tree();
  138. _update_group_tree();
  139. }
  140. void ProjectExportDialog::_rescan() {
  141. EditorFileSystem::get_singleton()->scan();
  142. }
  143. void ProjectExportDialog::_update_exporter() {
  144. }
  145. void ProjectExportDialog::_save_export_cfg() {
  146. EditorImportExport::get_singleton()->save_config();
  147. }
  148. void ProjectExportDialog::_prop_edited(String what) {
  149. _save_export_cfg();
  150. _validate_platform();
  151. }
  152. void ProjectExportDialog::_filters_edited(String what) {
  153. EditorImportExport::get_singleton()->set_export_custom_filter(what);
  154. _save_export_cfg();
  155. }
  156. void ProjectExportDialog::_filters_exclude_edited(String what) {
  157. EditorImportExport::get_singleton()->set_export_custom_filter_exclude(what);
  158. _save_export_cfg();
  159. }
  160. void ProjectExportDialog::_filters_exclude_dir_edited(String what) {
  161. EditorImportExport::get_singleton()->set_export_custom_filter_exclude_dir(what);
  162. _save_export_cfg();
  163. }
  164. void ProjectExportDialog::_quality_edited(float what) {
  165. EditorImportExport::get_singleton()->set_export_image_quality(what);
  166. _save_export_cfg();
  167. }
  168. void ProjectExportDialog::_shrink_edited(float what) {
  169. EditorImportExport::get_singleton()->set_export_image_shrink(what);
  170. _save_export_cfg();
  171. }
  172. void ProjectExportDialog::_image_export_edited(int what) {
  173. EditorImportExport::get_singleton()->set_export_image_action(EditorImportExport::ImageAction(what));
  174. _save_export_cfg();
  175. }
  176. void ProjectExportDialog::_format_toggled() {
  177. EditorImportExport::get_singleton()->get_image_formats().clear();
  178. for (int i = 0; i < formats.size(); i++) {
  179. if (formats[i]->is_checked(0))
  180. EditorImportExport::get_singleton()->get_image_formats().insert(formats[i]->get_text(0));
  181. }
  182. _save_export_cfg();
  183. }
  184. void ProjectExportDialog::_script_edited(Variant v) {
  185. if (updating_script)
  186. return;
  187. updating_script = true;
  188. EditorNode::get_undo_redo()->create_action(TTR("Edit Script Options"));
  189. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "script_set_action", script_mode->get_selected());
  190. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "script_set_action", EditorImportExport::get_singleton()->script_get_action());
  191. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "script_set_encryption_key", script_key->get_text());
  192. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "script_set_encryption_key", EditorImportExport::get_singleton()->script_get_encryption_key());
  193. EditorNode::get_undo_redo()->add_do_method(this, "_update_script");
  194. EditorNode::get_undo_redo()->add_undo_method(this, "_update_script");
  195. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  196. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  197. EditorNode::get_undo_redo()->commit_action();
  198. updating_script = false;
  199. }
  200. void ProjectExportDialog::_sample_convert_edited(int what) {
  201. EditorImportExport::get_singleton()->sample_set_action(EditorImportExport::SampleAction(sample_mode->get_selected()));
  202. EditorImportExport::get_singleton()->sample_set_max_hz(sample_max_hz->get_val());
  203. EditorImportExport::get_singleton()->sample_set_trim(sample_trim->is_pressed());
  204. _save_export_cfg();
  205. }
  206. void ProjectExportDialog::_notification(int p_what) {
  207. switch (p_what) {
  208. case NOTIFICATION_ENTER_TREE: {
  209. CenterContainer *cc = memnew(CenterContainer);
  210. TextureFrame *tf = memnew(TextureFrame);
  211. tf->set_texture(get_icon("ErrorSign", "EditorIcons"));
  212. cc->add_child(tf);
  213. plat_errors->add_child(cc);
  214. platform_error_string->raise();
  215. TreeItem *root = platforms->create_item(NULL);
  216. List<StringName> ep;
  217. EditorImportExport::get_singleton()->get_export_platforms(&ep);
  218. ep.sort_custom<StringName::AlphCompare>();
  219. for (List<StringName>::Element *E = ep.front(); E; E = E->next()) {
  220. Ref<EditorExportPlatform> eep = EditorImportExport::get_singleton()->get_export_platform(E->get());
  221. TreeItem *p = platforms->create_item(root);
  222. p->set_text(0, eep->get_name());
  223. p->set_icon(0, eep->get_logo());
  224. p->set_metadata(0, eep->get_name());
  225. if (eep->get_name() == OS::get_singleton()->get_name())
  226. p->select(0);
  227. }
  228. EditorFileSystem::get_singleton()->connect("filesystem_changed", this, "_scan_finished");
  229. // _rescan();
  230. _update_platform();
  231. export_mode->select(EditorImportExport::get_singleton()->get_export_filter());
  232. convert_text_scenes->set_pressed(EditorImportExport::get_singleton()->get_convert_text_scenes());
  233. filters->set_text(EditorImportExport::get_singleton()->get_export_custom_filter());
  234. filters_exclude->set_text(EditorImportExport::get_singleton()->get_export_custom_filter_exclude());
  235. filters_exclude_dir->set_text(EditorImportExport::get_singleton()->get_export_custom_filter_exclude_dir());
  236. if (EditorImportExport::get_singleton()->get_export_filter() != EditorImportExport::EXPORT_SELECTED)
  237. tree_vb->hide();
  238. else
  239. tree_vb->show();
  240. image_action->select(EditorImportExport::get_singleton()->get_export_image_action());
  241. image_quality->set_val(EditorImportExport::get_singleton()->get_export_image_quality());
  242. image_shrink->set_val(EditorImportExport::get_singleton()->get_export_image_shrink());
  243. _update_script();
  244. image_quality->connect("value_changed", this, "_quality_edited");
  245. image_shrink->connect("value_changed", this, "_shrink_edited");
  246. image_action->connect("item_selected", this, "_image_export_edited");
  247. script_mode->connect("item_selected", this, "_script_edited");
  248. script_key->connect("text_changed", this, "_script_edited");
  249. for (int i = 0; i < formats.size(); i++) {
  250. if (EditorImportExport::get_singleton()->get_image_formats().has(formats[i]->get_text(0)))
  251. formats[i]->set_checked(0, true);
  252. }
  253. image_formats->connect("item_edited", this, "_format_toggled");
  254. group_add->set_icon(get_icon("Add", "EditorIcons"));
  255. // group_del->set_icon(get_icon("Del","EditorIcons"));
  256. _update_group_list();
  257. _update_group();
  258. _update_group_tree();
  259. sample_mode->select(EditorImportExport::get_singleton()->sample_get_action());
  260. sample_max_hz->set_val(EditorImportExport::get_singleton()->sample_get_max_hz());
  261. sample_trim->set_pressed(EditorImportExport::get_singleton()->sample_get_trim());
  262. sample_mode->connect("item_selected", this, "_sample_convert_edited");
  263. sample_max_hz->connect("value_changed", this, "_sample_convert_edited");
  264. sample_trim->connect("toggled", this, "_sample_convert_edited");
  265. } break;
  266. case NOTIFICATION_EXIT_TREE: {
  267. } break;
  268. case MainLoop::NOTIFICATION_WM_FOCUS_IN: {
  269. //something may have changed
  270. _validate_platform();
  271. } break;
  272. case NOTIFICATION_VISIBILITY_CHANGED: {
  273. if (is_visible())
  274. _validate_platform();
  275. } break;
  276. case NOTIFICATION_PROCESS: {
  277. } break;
  278. }
  279. }
  280. void ProjectExportDialog::_validate_platform() {
  281. button_export->set_disabled(true);
  282. TreeItem *selected = platforms->get_selected();
  283. plat_errors->hide();
  284. if (!selected) {
  285. return;
  286. }
  287. String platform = selected->get_metadata(0);
  288. Ref<EditorExportPlatform> exporter = EditorImportExport::get_singleton()->get_export_platform(platform);
  289. if (!exporter.is_valid()) {
  290. return;
  291. }
  292. String err;
  293. if (!exporter->can_export(&err)) {
  294. Vector<String> items = err.strip_edges().split("\n");
  295. err = "";
  296. for (int i = 0; i < items.size(); i++) {
  297. if (i != 0)
  298. err += "\n";
  299. err += " -" + items[i];
  300. }
  301. platform_error_string->set_text(err);
  302. plat_errors->show();
  303. return;
  304. }
  305. List<String> pl;
  306. EditorFileSystem::get_singleton()->get_changed_sources(&pl);
  307. if (false && pl.size()) {
  308. if (pl.size() == 1)
  309. platform_error_string->set_text(" -One Resource is pending re-import.");
  310. else
  311. platform_error_string->set_text(" " + itos(pl.size()) + " Resources are pending re-import.");
  312. plat_errors->show();
  313. return;
  314. }
  315. button_export->set_disabled(false);
  316. }
  317. void ProjectExportDialog::_export_mode_changed(int p_idx) {
  318. if (EditorImportExport::get_singleton()->get_export_filter() == p_idx)
  319. return;
  320. EditorImportExport::get_singleton()->set_export_filter(EditorImportExport::ExportFilter(p_idx));
  321. if (p_idx != EditorImportExport::EXPORT_SELECTED)
  322. tree_vb->hide();
  323. else
  324. tree_vb->show();
  325. EditorImportExport::get_singleton()->set_convert_text_scenes(convert_text_scenes->is_pressed());
  326. _save_export_cfg();
  327. }
  328. void ProjectExportDialog::_export_action(const String &p_file) {
  329. String location = Globals::get_singleton()->globalize_path(p_file).get_base_dir().replace("\\", "/");
  330. while (true) {
  331. print_line("Loading engine file: " + location.plus_file("engine.cfg"));
  332. if (FileAccess::exists(location.plus_file("engine.cfg"))) {
  333. error->set_text(TTR("Please export outside the project folder!"));
  334. error->popup_centered_minsize();
  335. return;
  336. }
  337. String nl = (location + "/..").simplify_path();
  338. if (nl.find("/") == location.find_last("/"))
  339. break;
  340. location = nl;
  341. }
  342. /* Checked if the export location is outside the project directory,
  343. * now will check if a file name has been entered */
  344. if (p_file.ends_with("/")) {
  345. error->set_text("Please enter a file name!");
  346. error->popup_centered_minsize();
  347. return;
  348. }
  349. TreeItem *selected = platforms->get_selected();
  350. if (!selected)
  351. return;
  352. String platform = selected->get_metadata(0);
  353. bool debugging_enabled = EditorImportExport::get_singleton()->get_export_platform(platform)->is_debugging_enabled();
  354. Error err = export_platform(platform, p_file, debugging_enabled, file_export_password->get_text(), false);
  355. if (err != OK) {
  356. error->set_text(TTR("Error exporting project!"));
  357. error->popup_centered_minsize();
  358. }
  359. }
  360. void ProjectExportDialog::_export_action_pck(const String &p_file) {
  361. // we need a valid platform to get a functional platform exporter
  362. TreeItem *platform = platforms->get_last_item();
  363. if (!platform)
  364. return;
  365. Ref<EditorExportPlatform> exporter = EditorImportExport::get_singleton()->get_export_platform(platform->get_metadata(0));
  366. if (exporter.is_null()) {
  367. ERR_PRINT("Invalid platform for export of PCK");
  368. return;
  369. }
  370. if (p_file.ends_with(".pck")) {
  371. FileAccess *f = FileAccess::open(p_file, FileAccess::WRITE);
  372. if (!f) {
  373. error->set_text(TTR("Error writing the project PCK!"));
  374. error->popup_centered_minsize();
  375. }
  376. ERR_FAIL_COND(!f);
  377. Error err = exporter->save_pack(f, false);
  378. memdelete(f);
  379. if (err != OK) {
  380. error->set_text(TTR("Error exporting project!"));
  381. error->popup_centered_minsize();
  382. return;
  383. }
  384. } else if (p_file.ends_with(".zip")) {
  385. Error err = exporter->save_zip(p_file, false);
  386. if (err != OK) {
  387. error->set_text(TTR("Error exporting project!"));
  388. error->popup_centered_minsize();
  389. return;
  390. }
  391. }
  392. }
  393. Error ProjectExportDialog::export_platform(const String &p_platform, const String &p_path, bool p_debug, const String &p_password, bool p_quit_after) {
  394. Ref<EditorExportPlatform> exporter = EditorImportExport::get_singleton()->get_export_platform(p_platform);
  395. if (exporter.is_null()) {
  396. ERR_PRINT("Invalid platform for export");
  397. List<StringName> platforms;
  398. EditorImportExport::get_singleton()->get_export_platforms(&platforms);
  399. print_line("Valid export plaftorms are:");
  400. for (List<StringName>::Element *E = platforms.front(); E; E = E->next())
  401. print_line(" \"" + E->get() + "\"");
  402. if (p_quit_after) {
  403. OS::get_singleton()->set_exit_code(255);
  404. get_tree()->quit();
  405. }
  406. return ERR_INVALID_PARAMETER;
  407. }
  408. Error err = exporter->export_project(p_path, p_debug);
  409. if (err != OK) {
  410. error->set_text(TTR("Error exporting project!"));
  411. error->popup_centered_minsize();
  412. ERR_PRINT("Exporting failed!");
  413. if (p_quit_after) {
  414. OS::get_singleton()->set_exit_code(255);
  415. get_tree()->quit();
  416. }
  417. return ERR_CANT_CREATE;
  418. } else {
  419. if (p_quit_after) {
  420. get_tree()->quit();
  421. }
  422. }
  423. return OK;
  424. }
  425. void ProjectExportDialog::ok_pressed() {
  426. //export pck
  427. pck_export->popup_centered_ratio();
  428. }
  429. void ProjectExportDialog::custom_action(const String &) {
  430. //real export
  431. TreeItem *selected = platforms->get_selected();
  432. if (!selected)
  433. return;
  434. String platform = selected->get_metadata(0);
  435. Ref<EditorExportPlatform> exporter = EditorImportExport::get_singleton()->get_export_platform(platform);
  436. if (exporter.is_null()) {
  437. error->set_text(vformat(TTR("No exporter for platform '%s' yet."), platform));
  438. error->popup_centered_minsize();
  439. return;
  440. }
  441. if (platform.to_lower() == "android" && _check_android_setting(exporter) == false) {
  442. // not filled all field for Android release
  443. return;
  444. }
  445. String extension = exporter->get_binary_extension();
  446. file_export_password->set_editable(exporter->requires_password(exporter->is_debugging_enabled()));
  447. file_export->clear_filters();
  448. if (extension != "") {
  449. file_export->add_filter("*." + extension);
  450. }
  451. file_export->popup_centered_ratio();
  452. }
  453. LineEdit *ProjectExportDialog::_create_keystore_input(Control *container, const String &p_label, const String &name) {
  454. HBoxContainer *hb = memnew(HBoxContainer);
  455. Label *lb = memnew(Label);
  456. LineEdit *input = memnew(LineEdit);
  457. lb->set_text(p_label);
  458. lb->set_custom_minimum_size(Size2(140 * EDSCALE, 0));
  459. lb->set_align(Label::ALIGN_RIGHT);
  460. input->set_custom_minimum_size(Size2(170 * EDSCALE, 0));
  461. input->set_name(name);
  462. hb->add_constant_override("separation", 10 * EDSCALE);
  463. hb->add_child(lb);
  464. hb->add_child(input);
  465. container->add_child(hb);
  466. return input;
  467. }
  468. void ProjectExportDialog::_create_android_keystore_window() {
  469. keystore_file_dialog = memnew(EditorFileDialog);
  470. add_child(keystore_file_dialog);
  471. keystore_file_dialog->set_mode(EditorFileDialog::MODE_OPEN_DIR);
  472. keystore_file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  473. keystore_file_dialog->set_current_dir("res://");
  474. keystore_file_dialog->set_title(TTR("Target Path:"));
  475. keystore_file_dialog->connect("dir_selected", this, "_keystore_dir_selected");
  476. keystore_create_dialog = memnew(ConfirmationDialog);
  477. VBoxContainer *vb = memnew(VBoxContainer);
  478. vb->set_size(Size2(340 * EDSCALE, 0));
  479. keystore_create_dialog->set_title(TTR("Create Android keystore"));
  480. _create_keystore_input(vb, TTR("Full name"), "name");
  481. _create_keystore_input(vb, TTR("Organizational unit"), "unit");
  482. _create_keystore_input(vb, TTR("Organization"), "org");
  483. _create_keystore_input(vb, TTR("City"), "city");
  484. _create_keystore_input(vb, TTR("State"), "state");
  485. _create_keystore_input(vb, TTR("2 letter country code"), "code");
  486. _create_keystore_input(vb, TTR("User alias"), "alias");
  487. LineEdit *pass = _create_keystore_input(vb, TTR("Password"), "pass");
  488. pass->set_placeholder(TTR("at least 6 characters"));
  489. _create_keystore_input(vb, TTR("File name"), "file");
  490. Label *lb_path = memnew(Label);
  491. LineEdit *path = memnew(LineEdit);
  492. Button *btn = memnew(Button);
  493. HBoxContainer *hb = memnew(HBoxContainer);
  494. lb_path->set_text(TTR("Path : (better to save outside of project)"));
  495. path->set_h_size_flags(SIZE_EXPAND_FILL);
  496. path->set_name("path");
  497. btn->set_text(" .. ");
  498. btn->connect("pressed", keystore_file_dialog, "popup_centered_ratio");
  499. vb->add_spacer();
  500. vb->add_child(lb_path);
  501. hb->add_child(path);
  502. hb->add_child(btn);
  503. vb->add_child(hb);
  504. keystore_create_dialog->add_child(vb);
  505. keystore_create_dialog->set_child_rect(vb);
  506. add_child(keystore_create_dialog);
  507. keystore_create_dialog->connect("confirmed", this, "_create_android_keystore");
  508. path->connect("text_changed", this, "_check_keystore_path");
  509. confirm_keystore = memnew(ConfirmationDialog);
  510. confirm_keystore->connect("confirmed", keystore_create_dialog, "popup_centered_minsize");
  511. add_child(confirm_keystore);
  512. }
  513. void ProjectExportDialog::_keystore_dir_selected(const String &path) {
  514. LineEdit *edit = keystore_create_dialog->find_node("path", true, false)->cast_to<LineEdit>();
  515. edit->set_text(path.simplify_path());
  516. }
  517. void ProjectExportDialog::_keystore_created() {
  518. if (error->is_connected("popup_hide", this, "_keystore_created")) {
  519. error->disconnect("popup_hide", this, "_keystore_created");
  520. }
  521. custom_action("export_pck");
  522. }
  523. void ProjectExportDialog::_check_keystore_path(const String &path) {
  524. LineEdit *edit = keystore_create_dialog->find_node("path", true, false)->cast_to<LineEdit>();
  525. bool exists = DirAccess::exists(path);
  526. if (!exists) {
  527. edit->add_color_override("font_color", Color(1, 0, 0, 1));
  528. } else {
  529. edit->add_color_override("font_color", Color(0, 1, 0, 1));
  530. }
  531. }
  532. void ProjectExportDialog::_create_android_keystore() {
  533. Vector<String> names = String("name,unit,org,city,state,code,alias,pass").split(",");
  534. String path = keystore_create_dialog->find_node("path", true, false)->cast_to<LineEdit>()->get_text();
  535. String file = keystore_create_dialog->find_node("file", true, false)->cast_to<LineEdit>()->get_text();
  536. if (file.ends_with(".keystore") == false) {
  537. file += ".keystore";
  538. }
  539. String fullpath = path.plus_file(file);
  540. String info = "CN=$name, OU=$unit, O=$org, L=$city, S=$state, C=$code";
  541. Dictionary dic;
  542. for (int i = 0; i < names.size(); i++) {
  543. LineEdit *edit = keystore_create_dialog->find_node(names[i], true, false)->cast_to<LineEdit>();
  544. dic[names[i]] = edit->get_text();
  545. info = info.replace("$" + names[i], edit->get_text());
  546. }
  547. String jarsigner = EditorSettings::get_singleton()->get("android/jarsigner");
  548. String keytool = jarsigner.get_base_dir().plus_file("keytool");
  549. String os_name = OS::get_singleton()->get_name();
  550. if (os_name.to_lower() == "windows") {
  551. keytool += ".exe";
  552. }
  553. bool exist = FileAccess::exists(keytool);
  554. if (!exist) {
  555. error->set_text("Can't find 'keytool'");
  556. error->popup_centered_minsize();
  557. return;
  558. }
  559. List<String> args;
  560. args.push_back("-genkey");
  561. args.push_back("-v");
  562. args.push_back("-keystore");
  563. args.push_back(fullpath);
  564. args.push_back("-alias");
  565. args.push_back(dic["alias"]);
  566. args.push_back("-storepass");
  567. args.push_back(dic["pass"]);
  568. args.push_back("-keypass");
  569. args.push_back(dic["pass"]);
  570. args.push_back("-keyalg");
  571. args.push_back("RSA");
  572. args.push_back("-keysize");
  573. args.push_back("2048");
  574. args.push_back("-validity");
  575. args.push_back("10000");
  576. args.push_back("-dname");
  577. args.push_back(info);
  578. int retval;
  579. OS::get_singleton()->execute(keytool, args, true, NULL, NULL, &retval);
  580. if (retval == 0) { // success
  581. platform_options->_edit_set("keystore/release", fullpath);
  582. platform_options->_edit_set("keystore/release_user", dic["alias"]);
  583. platform_options->_edit_set("keystore/release_password", dic["pass"]);
  584. error->set_text("Android keystore created at \n" + fullpath);
  585. error->connect("popup_hide", this, "_keystore_created");
  586. error->popup_centered_minsize();
  587. } else { // fail
  588. error->set_text("Fail to create android keystore at \n" + fullpath);
  589. error->popup_centered_minsize();
  590. }
  591. }
  592. bool ProjectExportDialog::_check_android_setting(const Ref<EditorExportPlatform> &exporter) {
  593. bool is_debugging = exporter->get("debug/debugging_enabled");
  594. String release = exporter->get("keystore/release");
  595. String user = exporter->get("keystore/release_user");
  596. String password = exporter->get("keystore/release_password");
  597. if (!is_debugging && (release == "" || user == "" || password == "")) {
  598. if (release == "") {
  599. confirm_keystore->set_text(TTR("Release keystore is not set.\nDo you want to create one?"));
  600. confirm_keystore->popup_centered_minsize();
  601. } else {
  602. error->set_text(TTR("Fill Keystore/Release User and Release Password"));
  603. error->popup_centered_minsize();
  604. }
  605. return false;
  606. }
  607. return true;
  608. }
  609. void ProjectExportDialog::_group_selected() {
  610. _update_group(); //?
  611. _update_group_tree();
  612. }
  613. String ProjectExportDialog::_get_selected_group() {
  614. TreeItem *sel = groups->get_selected();
  615. if (!sel)
  616. return String();
  617. return sel->get_text(0);
  618. }
  619. void ProjectExportDialog::_update_group_list() {
  620. String current = _get_selected_group();
  621. groups->clear();
  622. List<StringName> grouplist;
  623. EditorImportExport::get_singleton()->image_export_get_groups(&grouplist);
  624. grouplist.sort_custom<StringName::AlphCompare>();
  625. TreeItem *r = groups->create_item();
  626. for (List<StringName>::Element *E = grouplist.front(); E; E = E->next()) {
  627. TreeItem *ti = groups->create_item(r);
  628. ti->set_text(0, E->get());
  629. ti->add_button(0, get_icon("Remove", "EditorIcons"));
  630. if (E->get() == current) {
  631. ti->select(0);
  632. }
  633. }
  634. _update_group();
  635. }
  636. void ProjectExportDialog::_select_group(const String &p_by_name) {
  637. TreeItem *c = groups->get_root();
  638. if (!c)
  639. return;
  640. c = c->get_children();
  641. if (!c)
  642. return;
  643. while (c) {
  644. if (c->get_text(0) == p_by_name) {
  645. c->select(0);
  646. _update_group();
  647. return;
  648. }
  649. c = c->get_next();
  650. }
  651. }
  652. void ProjectExportDialog::_update_group() {
  653. if (updating)
  654. return;
  655. updating = true;
  656. if (_get_selected_group() == "") {
  657. group_options->hide();
  658. //group_del->set_disabled(true);
  659. } else {
  660. group_options->show();
  661. //group_del->set_disabled(false);
  662. StringName name = _get_selected_group();
  663. group_image_action->select(EditorImportExport::get_singleton()->image_export_group_get_image_action(name));
  664. group_atlas->set_pressed(EditorImportExport::get_singleton()->image_export_group_get_make_atlas(name));
  665. group_shrink->set_val(EditorImportExport::get_singleton()->image_export_group_get_shrink(name));
  666. group_lossy_quality->set_val(EditorImportExport::get_singleton()->image_export_group_get_lossy_quality(name));
  667. if (group_atlas->is_pressed())
  668. atlas_preview->show();
  669. else
  670. atlas_preview->hide();
  671. }
  672. _update_group_tree();
  673. updating = false;
  674. }
  675. bool ProjectExportDialog::_update_group_treef(TreeItem *p_parent, EditorFileSystemDirectory *p_dir, const Set<String> &p_extensions, const String &p_groups, const Map<StringName, int> &p_group_index) {
  676. TreeItem *ti = group_images->create_item(p_parent);
  677. ti->set_text(0, p_dir->get_name() + "/");
  678. bool has_child = false;
  679. for (int i = 0; i < p_dir->get_subdir_count(); i++) {
  680. if (_update_group_treef(ti, p_dir->get_subdir(i), p_extensions, p_groups, p_group_index)) {
  681. has_child = true;
  682. }
  683. }
  684. String filter = group_images_filter->get_text();
  685. StringName current_group = _get_selected_group();
  686. String check_text = TTR("Include");
  687. for (int i = 0; i < p_dir->get_file_count(); i++) {
  688. String fname = p_dir->get_file(i);
  689. if (p_extensions.has(fname.to_lower().extension())) {
  690. String path = p_dir->get_file_path(i);
  691. if (filter != String() && path.find(filter) == -1)
  692. continue;
  693. has_child = true;
  694. TreeItem *file = group_images->create_item(ti);
  695. file->set_text(0, fname);
  696. StringName g = EditorImportExport::get_singleton()->image_get_export_group(path);
  697. if (current_group == g || g == StringName()) {
  698. file->set_cell_mode(1, TreeItem::CELL_MODE_CHECK);
  699. file->set_text(1, check_text);
  700. file->set_editable(1, true);
  701. file->set_checked(1, current_group == g);
  702. } else {
  703. file->set_text(1, g);
  704. file->set_editable(1, false);
  705. file->set_selectable(1, false);
  706. }
  707. file->set_metadata(0, path);
  708. }
  709. }
  710. if (!has_child) {
  711. memdelete(ti);
  712. return false;
  713. }
  714. return true;
  715. }
  716. void ProjectExportDialog::_update_group_tree() {
  717. if (updating)
  718. return;
  719. group_images->clear();
  720. if (_get_selected_group() == "")
  721. return;
  722. updating = true;
  723. print_line("****UGT");
  724. List<String> img_extensions;
  725. ImageLoader::get_recognized_extensions(&img_extensions);
  726. Set<String> extensions;
  727. for (List<String>::Element *E = img_extensions.front(); E; E = E->next()) {
  728. extensions.insert(E->get());
  729. }
  730. List<StringName> grouplist;
  731. EditorImportExport::get_singleton()->image_export_get_groups(&grouplist);
  732. grouplist.sort_custom<StringName::AlphCompare>();
  733. Map<StringName, int> group_index;
  734. group_index[StringName()] = 0;
  735. int idx = 1;
  736. String groupenum = "--";
  737. for (List<StringName>::Element *E = grouplist.front(); E; E = E->next()) {
  738. group_index[E->get()] = idx++;
  739. groupenum += "," + String(E->get());
  740. }
  741. updating = false;
  742. _update_group_treef(NULL, EditorFileSystem::get_singleton()->get_filesystem(), extensions, groupenum, group_index);
  743. }
  744. void ProjectExportDialog::_group_changed(Variant v) {
  745. if (updating)
  746. return;
  747. if (_get_selected_group() == "")
  748. return;
  749. updating = true;
  750. StringName name = _get_selected_group();
  751. EditorNode::get_undo_redo()->create_action(TTR("Change Image Group"));
  752. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_export_group_set_image_action", name, group_image_action->get_selected());
  753. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_export_group_set_make_atlas", name, group_atlas->is_pressed());
  754. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_export_group_set_shrink", name, group_shrink->get_val());
  755. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_export_group_set_lossy_quality", name, group_lossy_quality->get_val());
  756. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_image_action", name, EditorImportExport::get_singleton()->image_export_group_get_image_action(name));
  757. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_make_atlas", name, EditorImportExport::get_singleton()->image_export_group_get_make_atlas(name));
  758. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_shrink", name, EditorImportExport::get_singleton()->image_export_group_get_shrink(name));
  759. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_lossy_quality", name, EditorImportExport::get_singleton()->image_export_group_get_lossy_quality(name));
  760. EditorNode::get_undo_redo()->add_do_method(this, "_update_group");
  761. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group");
  762. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  763. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  764. EditorNode::get_undo_redo()->commit_action();
  765. updating = false;
  766. // update atlas preview button
  767. _update_group();
  768. }
  769. void ProjectExportDialog::_group_item_edited() {
  770. TreeItem *item = group_images->get_edited();
  771. if (!item)
  772. return;
  773. if (_get_selected_group() == String())
  774. return;
  775. StringName path = item->get_metadata(0);
  776. String group;
  777. if (item->is_checked(1)) {
  778. group = _get_selected_group();
  779. } else {
  780. group = String();
  781. }
  782. print_line("changed " + path + " to group: " + group);
  783. EditorNode::get_undo_redo()->create_action(TTR("Change Image Group"));
  784. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_add_to_export_group", path, group);
  785. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_add_to_export_group", path, EditorImportExport::get_singleton()->image_get_export_group(path));
  786. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_tree");
  787. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_tree");
  788. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  789. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  790. EditorNode::get_undo_redo()->commit_action();
  791. }
  792. void ProjectExportDialog::_group_add() {
  793. String name = group_new_name->get_text();
  794. if (name == "") {
  795. group_new_name_error->show();
  796. group_new_name_error->set_text(TTR("Group name can't be empty!"));
  797. return;
  798. }
  799. if (name.find("/") != -1 || name.find(":") != -1 || name.find(",") != -1 || name.find("-") != -1) {
  800. group_new_name_error->set_text(TTR("Invalid character in group name!"));
  801. group_new_name_error->show();
  802. return;
  803. }
  804. if (EditorImportExport::get_singleton()->image_export_has_group(name)) {
  805. group_new_name_error->set_text(TTR("Group name already exists!"));
  806. group_new_name_error->show();
  807. return;
  808. }
  809. group_new_name_error->hide();
  810. String current = _get_selected_group();
  811. EditorNode::get_undo_redo()->create_action(TTR("Add Image Group"));
  812. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_export_group_create", name);
  813. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_remove", name);
  814. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_list");
  815. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_list");
  816. EditorNode::get_undo_redo()->add_do_method(this, "_select_group", name);
  817. if (current != "")
  818. EditorNode::get_undo_redo()->add_undo_method(this, "_select_group", current);
  819. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_tree");
  820. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_tree");
  821. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  822. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  823. EditorNode::get_undo_redo()->commit_action();
  824. }
  825. void ProjectExportDialog::_group_del(Object *p_item, int p_column, int p_button) {
  826. TreeItem *item = p_item->cast_to<TreeItem>();
  827. if (!item)
  828. return;
  829. String name = item->get_text(0);
  830. EditorNode::get_undo_redo()->create_action(TTR("Delete Image Group"));
  831. List<StringName> images_used;
  832. EditorImportExport::get_singleton()->image_export_get_images_in_group(name, &images_used);
  833. for (List<StringName>::Element *E = images_used.front(); E; E = E->next()) {
  834. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_add_to_export_group", E->get(), StringName());
  835. }
  836. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_export_group_remove", name);
  837. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_create", name);
  838. for (List<StringName>::Element *E = images_used.front(); E; E = E->next()) {
  839. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_add_to_export_group", E->get(), name);
  840. }
  841. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_image_action", name, EditorImportExport::get_singleton()->image_export_group_get_image_action(name));
  842. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_make_atlas", name, EditorImportExport::get_singleton()->image_export_group_get_make_atlas(name));
  843. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_shrink", name, EditorImportExport::get_singleton()->image_export_group_get_shrink(name));
  844. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_export_group_set_lossy_quality", name, EditorImportExport::get_singleton()->image_export_group_get_lossy_quality(name));
  845. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_list");
  846. EditorNode::get_undo_redo()->add_do_method(this, "_update_group");
  847. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_list");
  848. EditorNode::get_undo_redo()->add_undo_method(this, "_select_group", name);
  849. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_tree");
  850. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_tree");
  851. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  852. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  853. EditorNode::get_undo_redo()->commit_action();
  854. }
  855. void ProjectExportDialog::_group_select_all() {
  856. String group = _get_selected_group();
  857. if (group == "")
  858. return;
  859. TreeItem *item = group_images->get_root();
  860. if (!item)
  861. return;
  862. List<StringName> items;
  863. while (item) {
  864. if (item->get_cell_mode(1) == TreeItem::CELL_MODE_CHECK && !item->is_checked(1))
  865. items.push_back(item->get_metadata(0));
  866. item = item->get_next_visible();
  867. }
  868. if (items.size() == 0)
  869. return;
  870. EditorNode::get_undo_redo()->create_action(TTR("Select All"));
  871. for (List<StringName>::Element *E = items.front(); E; E = E->next()) {
  872. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_add_to_export_group", E->get(), group);
  873. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_add_to_export_group", E->get(), String());
  874. }
  875. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_tree");
  876. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_tree");
  877. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  878. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  879. EditorNode::get_undo_redo()->commit_action();
  880. }
  881. void ProjectExportDialog::_group_select_none() {
  882. String group = _get_selected_group();
  883. if (group == "")
  884. return;
  885. TreeItem *item = group_images->get_root();
  886. if (!item)
  887. return;
  888. List<StringName> items;
  889. while (item) {
  890. if (item->get_cell_mode(1) == TreeItem::CELL_MODE_CHECK && item->is_checked(1))
  891. items.push_back(item->get_metadata(0));
  892. item = item->get_next_visible();
  893. }
  894. if (items.size() == 0)
  895. return;
  896. EditorNode::get_undo_redo()->create_action(TTR("Select All"));
  897. for (List<StringName>::Element *E = items.front(); E; E = E->next()) {
  898. EditorNode::get_undo_redo()->add_do_method(EditorImportExport::get_singleton(), "image_add_to_export_group", E->get(), String());
  899. EditorNode::get_undo_redo()->add_undo_method(EditorImportExport::get_singleton(), "image_add_to_export_group", E->get(), group);
  900. }
  901. EditorNode::get_undo_redo()->add_do_method(this, "_update_group_tree");
  902. EditorNode::get_undo_redo()->add_undo_method(this, "_update_group_tree");
  903. EditorNode::get_undo_redo()->add_do_method(this, "_save_export_cfg");
  904. EditorNode::get_undo_redo()->add_undo_method(this, "_save_export_cfg");
  905. EditorNode::get_undo_redo()->commit_action();
  906. }
  907. void ProjectExportDialog::_group_atlas_preview() {
  908. StringName group = _get_selected_group();
  909. if (!group)
  910. return;
  911. atlas_preview_frame->set_texture(Ref<Texture>()); //clear previous
  912. List<StringName> images;
  913. EditorImportExport::get_singleton()->image_export_get_images_in_group(group, &images);
  914. images.sort_custom<StringName::AlphCompare>();
  915. String dst_file = EditorSettings::get_singleton()->get_settings_path() + "/tmp/atlas-preview.tex";
  916. Ref<ResourceImportMetadata> imd = memnew(ResourceImportMetadata);
  917. //imd->set_editor();
  918. for (List<StringName>::Element *F = images.front(); F; F = F->next()) {
  919. imd->add_source(EditorImportPlugin::validate_source_path(F->get()));
  920. }
  921. int flags = 0;
  922. if (Globals::get_singleton()->get("image_loader/filter"))
  923. flags |= EditorTextureImportPlugin::IMAGE_FLAG_FILTER;
  924. if (!Globals::get_singleton()->get("image_loader/gen_mipmaps"))
  925. flags |= EditorTextureImportPlugin::IMAGE_FLAG_NO_MIPMAPS;
  926. if (!Globals::get_singleton()->get("image_loader/repeat"))
  927. flags |= EditorTextureImportPlugin::IMAGE_FLAG_REPEAT;
  928. flags |= EditorTextureImportPlugin::IMAGE_FLAG_FIX_BORDER_ALPHA;
  929. imd->set_option("format", EditorTextureImportPlugin::IMAGE_FORMAT_COMPRESS_DISK_LOSSLESS);
  930. imd->set_option("flags", flags);
  931. imd->set_option("quality", 0.7);
  932. imd->set_option("atlas", true);
  933. imd->set_option("crop", true);
  934. Ref<EditorTextureImportPlugin> plugin = EditorImportExport::get_singleton()->get_import_plugin_by_name("texture");
  935. Error err = plugin->import2(dst_file, imd, EditorExportPlatform::IMAGE_COMPRESSION_NONE, true);
  936. if (err) {
  937. EditorNode::add_io_error(TTR("Error saving atlas:") + " " + dst_file.get_file());
  938. return;
  939. }
  940. Ref<Texture> tex = ResourceLoader::load(dst_file);
  941. atlas_preview_frame->set_texture(tex); //clear previous
  942. atlas_preview_dialog->set_title(TTR("Atlas Preview") + " (" + itos(tex->get_width()) + "x" + itos(tex->get_height()) + ")");
  943. atlas_preview_dialog->popup_centered_ratio(0.9);
  944. }
  945. void ProjectExportDialog::_update_script() {
  946. if (updating_script)
  947. return;
  948. updating_script = true;
  949. script_mode->select(EditorImportExport::get_singleton()->script_get_action());
  950. script_key->set_text(EditorImportExport::get_singleton()->script_get_encryption_key());
  951. updating_script = false;
  952. }
  953. void ProjectExportDialog::_image_filter_changed(String) {
  954. _update_group_tree();
  955. }
  956. void ProjectExportDialog::_bind_methods() {
  957. ObjectTypeDB::bind_method(_MD("_rescan"), &ProjectExportDialog::_rescan);
  958. ObjectTypeDB::bind_method(_MD("_tree_changed"), &ProjectExportDialog::_tree_changed);
  959. ObjectTypeDB::bind_method(_MD("_scan_finished"), &ProjectExportDialog::_scan_finished);
  960. ObjectTypeDB::bind_method(_MD("_platform_selected"), &ProjectExportDialog::_platform_selected);
  961. ObjectTypeDB::bind_method(_MD("_prop_edited"), &ProjectExportDialog::_prop_edited);
  962. ObjectTypeDB::bind_method(_MD("_export_mode_changed"), &ProjectExportDialog::_export_mode_changed);
  963. ObjectTypeDB::bind_method(_MD("_filters_edited"), &ProjectExportDialog::_filters_edited);
  964. ObjectTypeDB::bind_method(_MD("_filters_exclude_edited"), &ProjectExportDialog::_filters_exclude_edited);
  965. ObjectTypeDB::bind_method(_MD("_filters_exclude_dir_edited"), &ProjectExportDialog::_filters_exclude_dir_edited);
  966. ObjectTypeDB::bind_method(_MD("_export_action"), &ProjectExportDialog::_export_action);
  967. ObjectTypeDB::bind_method(_MD("_export_action_pck"), &ProjectExportDialog::_export_action_pck);
  968. ObjectTypeDB::bind_method(_MD("_quality_edited"), &ProjectExportDialog::_quality_edited);
  969. ObjectTypeDB::bind_method(_MD("_shrink_edited"), &ProjectExportDialog::_shrink_edited);
  970. ObjectTypeDB::bind_method(_MD("_image_export_edited"), &ProjectExportDialog::_image_export_edited);
  971. ObjectTypeDB::bind_method(_MD("_format_toggled"), &ProjectExportDialog::_format_toggled);
  972. ObjectTypeDB::bind_method(_MD("_group_changed"), &ProjectExportDialog::_group_changed);
  973. ObjectTypeDB::bind_method(_MD("_group_add"), &ProjectExportDialog::_group_add);
  974. ObjectTypeDB::bind_method(_MD("_group_del"), &ProjectExportDialog::_group_del);
  975. ObjectTypeDB::bind_method(_MD("_group_selected"), &ProjectExportDialog::_group_selected);
  976. ObjectTypeDB::bind_method(_MD("_update_group"), &ProjectExportDialog::_update_group);
  977. ObjectTypeDB::bind_method(_MD("_update_group_list"), &ProjectExportDialog::_update_group_list);
  978. ObjectTypeDB::bind_method(_MD("_select_group"), &ProjectExportDialog::_select_group);
  979. ObjectTypeDB::bind_method(_MD("_update_group_tree"), &ProjectExportDialog::_update_group_tree);
  980. ObjectTypeDB::bind_method(_MD("_group_item_edited"), &ProjectExportDialog::_group_item_edited);
  981. ObjectTypeDB::bind_method(_MD("_save_export_cfg"), &ProjectExportDialog::_save_export_cfg);
  982. ObjectTypeDB::bind_method(_MD("_image_filter_changed"), &ProjectExportDialog::_image_filter_changed);
  983. ObjectTypeDB::bind_method(_MD("_group_atlas_preview"), &ProjectExportDialog::_group_atlas_preview);
  984. ObjectTypeDB::bind_method(_MD("_group_select_all"), &ProjectExportDialog::_group_select_all);
  985. ObjectTypeDB::bind_method(_MD("_group_select_none"), &ProjectExportDialog::_group_select_none);
  986. ObjectTypeDB::bind_method(_MD("_script_edited"), &ProjectExportDialog::_script_edited);
  987. ObjectTypeDB::bind_method(_MD("_update_script"), &ProjectExportDialog::_update_script);
  988. ObjectTypeDB::bind_method(_MD("_sample_convert_edited"), &ProjectExportDialog::_sample_convert_edited);
  989. ObjectTypeDB::bind_method(_MD("export_platform"), &ProjectExportDialog::export_platform);
  990. ObjectTypeDB::bind_method(_MD("_create_android_keystore"), &ProjectExportDialog::_create_android_keystore);
  991. ObjectTypeDB::bind_method(_MD("_check_keystore_path"), &ProjectExportDialog::_check_keystore_path);
  992. ObjectTypeDB::bind_method(_MD("_keystore_dir_selected"), &ProjectExportDialog::_keystore_dir_selected);
  993. ObjectTypeDB::bind_method(_MD("_keystore_created"), &ProjectExportDialog::_keystore_created);
  994. // ADD_SIGNAL(MethodInfo("instance"));
  995. // ADD_SIGNAL(MethodInfo("open"));
  996. }
  997. ProjectExportDialog::ProjectExportDialog(EditorNode *p_editor) {
  998. editor = p_editor;
  999. set_title(TTR("Project Export Settings"));
  1000. sections = memnew(TabContainer);
  1001. add_child(sections);
  1002. set_child_rect(sections);
  1003. VBoxContainer *pvbox = memnew(VBoxContainer);
  1004. sections->add_child(pvbox);
  1005. pvbox->set_name(TTR("Target"));
  1006. HBoxContainer *phbox = memnew(HBoxContainer);
  1007. pvbox->add_child(phbox);
  1008. phbox->set_v_size_flags(SIZE_EXPAND_FILL);
  1009. plat_errors = memnew(HBoxContainer);
  1010. pvbox->add_child(plat_errors);
  1011. platform_error_string = memnew(Label);
  1012. platform_error_string->set_h_size_flags(SIZE_EXPAND_FILL);
  1013. plat_errors->add_child(platform_error_string);
  1014. VBoxContainer *vb = memnew(VBoxContainer);
  1015. vb->set_h_size_flags(SIZE_EXPAND_FILL);
  1016. vb->set_v_size_flags(SIZE_EXPAND_FILL);
  1017. phbox->add_child(vb);
  1018. platforms = memnew(Tree);
  1019. platforms->set_hide_root(true);
  1020. vb->add_margin_child(TTR("Export to Platform"), platforms, true);
  1021. platforms->connect("cell_selected", this, "_platform_selected");
  1022. vb = memnew(VBoxContainer);
  1023. phbox->add_child(vb);
  1024. vb->set_h_size_flags(SIZE_EXPAND_FILL);
  1025. vb->set_v_size_flags(SIZE_EXPAND_FILL);
  1026. platform_options = memnew(PropertyEditor());
  1027. platform_options->hide_top_label();
  1028. vb->add_margin_child(TTR("Options"), platform_options, true);
  1029. platform_options->connect("property_edited", this, "_prop_edited");
  1030. //////////////////
  1031. vb = memnew(VBoxContainer);
  1032. vb->set_name(TTR("Resources"));
  1033. sections->add_child(vb);
  1034. export_mode = memnew(OptionButton);
  1035. export_mode->add_item(TTR("Export selected resources (including dependencies)."));
  1036. export_mode->add_item(TTR("Export all resources in the project."));
  1037. export_mode->add_item(TTR("Export all files in the project directory."));
  1038. export_mode->connect("item_selected", this, "_export_mode_changed");
  1039. vb->add_margin_child(TTR("Export Mode:"), export_mode);
  1040. tree_vb = memnew(VBoxContainer);
  1041. vb->add_child(tree_vb);
  1042. tree_vb->set_v_size_flags(SIZE_EXPAND_FILL);
  1043. tree = memnew(Tree);
  1044. tree_vb->add_margin_child(TTR("Resources to Export:"), tree, true);
  1045. tree->set_v_size_flags(SIZE_EXPAND_FILL);
  1046. tree->connect("item_edited", this, "_tree_changed");
  1047. tree->set_columns(2);
  1048. tree->set_column_titles_visible(true);
  1049. tree->set_column_title(0, TTR("File"));
  1050. tree->set_column_title(1, TTR("Action"));
  1051. tree->set_column_expand(1, false);
  1052. tree->set_column_min_width(1, 90);
  1053. filters = memnew(LineEdit);
  1054. vb->add_margin_child(TTR("Filters to export non-resource files (comma-separated, e.g.: *.json, *.txt):"), filters);
  1055. filters->connect("text_changed", this, "_filters_edited");
  1056. filters_exclude = memnew(LineEdit);
  1057. vb->add_margin_child(TTR("Filters to exclude from export (comma-separated, e.g.: *.json, *.txt):"), filters_exclude);
  1058. filters_exclude->connect("text_changed", this, "_filters_exclude_edited");
  1059. filters_exclude_dir = memnew(LineEdit);
  1060. vb->add_margin_child(TTR("Filters to exclude directories from export (comma-separated, e.g.: addons, devs, test):"), filters_exclude_dir);
  1061. filters_exclude_dir->connect("text_changed", this, "_filters_exclude_dir_edited");
  1062. convert_text_scenes = memnew(CheckButton);
  1063. convert_text_scenes->set_text(TTR("Convert text scenes to binary on export."));
  1064. vb->add_child(convert_text_scenes);
  1065. convert_text_scenes->connect("toggled", this, "_export_mode_changed");
  1066. image_vb = memnew(VBoxContainer);
  1067. image_vb->set_name(TTR("Images"));
  1068. image_action = memnew(OptionButton);
  1069. image_action->add_item(TTR("Keep Original"));
  1070. image_action->add_item(TTR("Compress for Disk (Lossy, WebP)"));
  1071. image_action->add_item(TTR("Compress for RAM (BC/PVRTC/ETC)"));
  1072. image_vb->add_margin_child(TTR("Convert Images (*.png):"), image_action);
  1073. HBoxContainer *qhb = memnew(HBoxContainer);
  1074. image_quality = memnew(HSlider);
  1075. qhb->add_child(image_quality);
  1076. image_quality->set_h_size_flags(SIZE_EXPAND_FILL);
  1077. SpinBox *qspin = memnew(SpinBox);
  1078. image_quality->share(qspin);
  1079. qhb->add_child(qspin);
  1080. image_quality->set_min(0);
  1081. image_quality->set_max(1);
  1082. image_quality->set_step(0.01);
  1083. image_vb->add_margin_child(TTR("Compress for Disk (Lossy) Quality:"), qhb);
  1084. image_shrink = memnew(SpinBox);
  1085. image_shrink->set_min(1);
  1086. image_shrink->set_max(8);
  1087. image_shrink->set_step(0.1);
  1088. image_vb->add_margin_child(TTR("Shrink All Images:"), image_shrink);
  1089. sections->add_child(image_vb);
  1090. image_formats = memnew(Tree);
  1091. image_formats->set_hide_root(true);
  1092. TreeItem *root = image_formats->create_item(NULL);
  1093. List<String> fmts;
  1094. ImageLoader::get_recognized_extensions(&fmts);
  1095. for (List<String>::Element *E = fmts.front(); E; E = E->next()) {
  1096. TreeItem *fmt = image_formats->create_item(root);
  1097. fmt->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  1098. fmt->set_text(0, E->get());
  1099. fmt->set_editable(0, true);
  1100. formats.push_back(fmt);
  1101. }
  1102. image_vb->add_margin_child(TTR("Compress Formats:") + " ", image_formats, true);
  1103. /// groups
  1104. HBoxContainer *group_hb = memnew(HBoxContainer);
  1105. group_hb->set_name(TTR("Image Groups"));
  1106. sections->add_child(group_hb);
  1107. VBoxContainer *group_vb_left = memnew(VBoxContainer);
  1108. group_hb->add_child(group_vb_left);
  1109. VBoxContainer *gvb = memnew(VBoxContainer);
  1110. HBoxContainer *ghb = memnew(HBoxContainer);
  1111. gvb->add_child(ghb);
  1112. group_new_name = memnew(LineEdit);
  1113. group_new_name->set_h_size_flags(SIZE_EXPAND_FILL);
  1114. ghb->add_child(group_new_name);
  1115. group_add = memnew(ToolButton);
  1116. group_add->connect("pressed", this, "_group_add");
  1117. ghb->add_child(group_add);
  1118. group_new_name_error = memnew(Label);
  1119. group_new_name_error->add_color_override("font_color", Color(1, 0.4, 0.4));
  1120. gvb->add_child(group_new_name_error);
  1121. group_new_name_error->hide();
  1122. groups = memnew(Tree);
  1123. groups->set_v_size_flags(SIZE_EXPAND_FILL);
  1124. groups->connect("cell_selected", this, "_group_selected", varray(), CONNECT_DEFERRED);
  1125. groups->connect("button_pressed", this, "_group_del", varray(), CONNECT_DEFERRED);
  1126. groups->set_hide_root(true);
  1127. gvb->add_child(groups);
  1128. group_vb_left->add_margin_child(TTR("Groups:"), gvb, true);
  1129. //group_vb_left->add_child( memnew( HSeparator));
  1130. group_options = memnew(VBoxContainer);
  1131. group_vb_left->add_child(group_options);
  1132. group_image_action = memnew(OptionButton);
  1133. group_image_action->add_item(TTR("Default"));
  1134. group_image_action->add_item(TTR("Compress Disk"));
  1135. group_image_action->add_item(TTR("Compress RAM"));
  1136. group_image_action->add_item(TTR("Keep Original"));
  1137. group_options->add_margin_child(TTR("Compress Mode:"), group_image_action);
  1138. group_image_action->connect("item_selected", this, "_group_changed");
  1139. group_lossy_quality = memnew(HSlider);
  1140. group_lossy_quality->set_min(0.1);
  1141. group_lossy_quality->set_max(1.0);
  1142. group_lossy_quality->set_step(0.01);
  1143. group_lossy_quality->set_val(0.7);
  1144. group_lossy_quality->connect("value_changed", this, "_quality_edited");
  1145. HBoxContainer *gqhb = memnew(HBoxContainer);
  1146. SpinBox *gqspin = memnew(SpinBox);
  1147. group_lossy_quality->share(gqspin);
  1148. group_lossy_quality->set_h_size_flags(SIZE_EXPAND_FILL);
  1149. gqhb->add_child(group_lossy_quality);
  1150. gqhb->add_child(gqspin);
  1151. group_options->add_margin_child(TTR("Lossy Quality:"), gqhb);
  1152. group_atlas = memnew(CheckButton);
  1153. group_atlas->set_pressed(true);
  1154. group_options->add_margin_child(TTR("Atlas:"), group_atlas);
  1155. group_atlas->connect("toggled", this, "_group_changed");
  1156. group_shrink = memnew(SpinBox);
  1157. group_shrink->set_min(1);
  1158. group_shrink->set_max(8);
  1159. group_shrink->set_val(1);
  1160. group_shrink->set_step(0.001);
  1161. group_options->add_margin_child(TTR("Shrink By:"), group_shrink);
  1162. group_shrink->connect("value_changed", this, "_group_changed");
  1163. atlas_preview = memnew(Button);
  1164. atlas_preview->set_text(TTR("Preview Atlas"));
  1165. group_options->add_child(atlas_preview);
  1166. atlas_preview->show();
  1167. atlas_preview->connect("pressed", this, "_group_atlas_preview");
  1168. Control *ec = memnew(Control);
  1169. ec->set_custom_minimum_size(Size2(150, 1));
  1170. gvb->add_child(ec);
  1171. VBoxContainer *group_vb_right = memnew(VBoxContainer);
  1172. group_hb->add_child(group_vb_right);
  1173. group_vb_right->set_h_size_flags(SIZE_EXPAND_FILL);
  1174. HBoxContainer *filter_hb = memnew(HBoxContainer);
  1175. group_images_filter = memnew(LineEdit);
  1176. group_vb_right->add_margin_child(TTR("Image Filter:"), filter_hb);
  1177. filter_hb->add_child(group_images_filter);
  1178. group_images_filter->set_h_size_flags(SIZE_EXPAND_FILL);
  1179. group_images_filter->connect("text_changed", this, "_image_filter_changed");
  1180. group_images = memnew(Tree);
  1181. group_images->set_v_size_flags(SIZE_EXPAND_FILL);
  1182. group_vb_right->add_margin_child(TTR("Images:"), group_images, true);
  1183. Button *filt_select_all = memnew(Button);
  1184. filt_select_all->set_text(TTR("Select All"));
  1185. filter_hb->add_child(filt_select_all);
  1186. filt_select_all->connect("pressed", this, "_group_select_all");
  1187. Button *filt_select_none = memnew(Button);
  1188. filt_select_none->set_text(TTR("Select None"));
  1189. filter_hb->add_child(filt_select_none);
  1190. filt_select_none->connect("pressed", this, "_group_select_none");
  1191. atlas_preview_dialog = memnew(AcceptDialog);
  1192. ScrollContainer *scroll = memnew(ScrollContainer);
  1193. atlas_preview_dialog->add_child(scroll);
  1194. atlas_preview_dialog->set_child_rect(scroll);
  1195. atlas_preview_frame = memnew(TextureFrame);
  1196. scroll->add_child(atlas_preview_frame);
  1197. add_child(atlas_preview_dialog);
  1198. group_images->set_hide_root(true);
  1199. group_images->set_columns(2);
  1200. group_images->set_column_expand(0, true);
  1201. group_images->set_column_expand(1, false);
  1202. group_images->set_column_min_width(1, 100);
  1203. group_images->set_column_titles_visible(true);
  1204. group_images->set_column_title(0, TTR("Images"));
  1205. group_images->set_column_title(1, TTR("Group"));
  1206. group_images->connect("item_edited", this, "_group_item_edited", varray(), CONNECT_DEFERRED);
  1207. /* SpinBox *group_shrink;
  1208. CheckButton *group_atlas;
  1209. OptionButton *group_image_action;*/
  1210. /* progress = memnew( Label );
  1211. add_child(progress);
  1212. progress->set_area_as_parent_rect();
  1213. progress->set_anchor_and_margin(MARGIN_TOP,Control::ANCHOR_BEGIN,25);
  1214. progress->hide();
  1215. progress->set_align(Label::ALIGN_CENTER);*/
  1216. /*
  1217. button_reload = memnew( Button );
  1218. button_reload->set_pos(Point2(3,2));
  1219. button_reload->set_size(Point2(20,5));
  1220. button_reload->set_flat(true);
  1221. //add_child(button_reload);
  1222. button_reload->connect("pressed",this,"_rescan");
  1223. hbc->add_child(button_reload);
  1224. */
  1225. sample_vbox = memnew(VBoxContainer);
  1226. sample_vbox->set_name(TTR("Samples"));
  1227. sections->add_child(sample_vbox);
  1228. sample_mode = memnew(OptionButton);
  1229. sample_vbox->add_margin_child(TTR("Sample Conversion Mode: (.wav files):"), sample_mode);
  1230. sample_mode->add_item(TTR("Keep"));
  1231. sample_mode->add_item(TTR("Compress (RAM - IMA-ADPCM)"));
  1232. sample_max_hz = memnew(SpinBox);
  1233. sample_max_hz->set_max(192000);
  1234. sample_max_hz->set_min(8000);
  1235. sample_vbox->add_margin_child(TTR("Sampling Rate Limit (Hz):"), sample_max_hz);
  1236. sample_trim = memnew(CheckButton);
  1237. sample_trim->set_text(TTR("Trim"));
  1238. sample_vbox->add_margin_child(TTR("Trailing Silence:"), sample_trim);
  1239. script_vbox = memnew(VBoxContainer);
  1240. script_vbox->set_name(TTR("Script"));
  1241. sections->add_child(script_vbox);
  1242. script_mode = memnew(OptionButton);
  1243. script_vbox->add_margin_child(TTR("Script Export Mode:"), script_mode);
  1244. script_mode->add_item(TTR("Text"));
  1245. script_mode->add_item(TTR("Compiled"));
  1246. script_mode->add_item(TTR("Encrypted (Provide Key Below)"));
  1247. script_key = memnew(LineEdit);
  1248. script_vbox->add_margin_child(TTR("Script Encryption Key (256-bits as hex):"), script_key);
  1249. updating = false;
  1250. error = memnew(AcceptDialog);
  1251. add_child(error);
  1252. confirm = memnew(ConfirmationDialog);
  1253. add_child(confirm);
  1254. confirm->connect("confirmed", this, "_confirmed");
  1255. get_ok()->set_text(TTR("Export PCK/Zip"));
  1256. expopt = "--,Export,Bundle";
  1257. file_export = memnew(EditorFileDialog);
  1258. add_child(file_export);
  1259. file_export->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  1260. file_export->set_current_dir(EditorSettings::get_singleton()->get("global/default_project_export_path"));
  1261. file_export->set_title(TTR("Export Project"));
  1262. file_export->connect("file_selected", this, "_export_action");
  1263. file_export_password = memnew(LineEdit);
  1264. file_export_password->set_secret(true);
  1265. file_export_password->set_editable(false);
  1266. file_export->get_vbox()->add_margin_child(TTR("Password:"), file_export_password);
  1267. pck_export = memnew(EditorFileDialog);
  1268. pck_export->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  1269. pck_export->set_current_dir(EditorSettings::get_singleton()->get("global/default_project_export_path"));
  1270. pck_export->set_title(TTR("Export Project PCK"));
  1271. pck_export->connect("file_selected", this, "_export_action_pck");
  1272. pck_export->add_filter("*.pck ; Data Pack");
  1273. pck_export->add_filter("*.zip ; Zip");
  1274. add_child(pck_export);
  1275. button_export = add_button(TTR("Export.."), !OS::get_singleton()->get_swap_ok_cancel(), "export_pck");
  1276. updating_script = false;
  1277. ei = "EditorIcons";
  1278. ot = "Object";
  1279. pending_update_tree = true;
  1280. _create_android_keystore_window();
  1281. }
  1282. ProjectExportDialog::~ProjectExportDialog() {
  1283. }
  1284. void ProjectExport::popup_export() {
  1285. Set<String> presets;
  1286. presets.insert("default");
  1287. List<PropertyInfo> pi;
  1288. Globals::get_singleton()->get_property_list(&pi);
  1289. export_preset->clear();
  1290. for (List<PropertyInfo>::Element *E = pi.front(); E; E = E->next()) {
  1291. if (!E->get().name.begins_with("export_presets/"))
  1292. continue;
  1293. presets.insert(E->get().name.get_slice("/", 1));
  1294. }
  1295. for (Set<String>::Element *E = presets.front(); E; E = E->next()) {
  1296. export_preset->add_item(E->get());
  1297. }
  1298. popup_centered(Size2(300, 100));
  1299. }
  1300. Error ProjectExport::export_project(const String &p_preset) {
  1301. return OK;
  1302. #if 0
  1303. String selected=p_preset;
  1304. DVector<String> preset_settings = Globals::get_singleton()->get("export_presets/"+selected);
  1305. String preset_path=Globals::get_singleton()->get("export_presets_path/"+selected);
  1306. if (preset_path=="") {
  1307. error->set_text("Export path empty, see export options");
  1308. error->popup_centered_minsize(Size2(300,100));
  1309. ERR_FAIL_V(ERR_INVALID_DATA);
  1310. }
  1311. int pc=preset_settings.size();
  1312. DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
  1313. if (d->change_dir(preset_path)!=OK) {
  1314. memdelete(d);
  1315. error->set_text("Can't access to export path:\n "+preset_path);
  1316. error->popup_centered_minsize(Size2(300,100));
  1317. ERR_FAIL_V(ERR_INVALID_DATA);
  1318. }
  1319. if (pc==0) {
  1320. memdelete(d);
  1321. return OK;
  1322. }
  1323. if (pc%3 != 0 ) {
  1324. memdelete(d);
  1325. error->set_text("Corrupted export data..");
  1326. error->popup_centered_minsize(Size2(300,100));
  1327. ERR_EXPLAIN("Corrupted export data...");
  1328. ERR_FAIL_V(ERR_INVALID_DATA);
  1329. }
  1330. Map<String,ProjectExportSettings::ItemData> export_action;
  1331. Map<String,Map<String,String> > remapped_paths;
  1332. Set<String> scene_extensions;
  1333. Set<String> resource_extensions;
  1334. {
  1335. List<String> l;
  1336. // SceneLoader::get_recognized_extensions(&l);
  1337. // for(List<String>::Element *E=l.front();E;E=E->next()) {
  1338. //
  1339. // scene_extensions.insert(E->get());
  1340. // }
  1341. ResourceLoader::get_recognized_extensions_for_type("",&l);
  1342. for(List<String>::Element *E=l.front();E;E=E->next()) {
  1343. resource_extensions.insert(E->get());
  1344. }
  1345. }
  1346. Vector<String> names = Globals::get_singleton()->get_optimizer_presets();
  1347. //prepare base paths
  1348. for(int i=0;i<pc;i+=3) {
  1349. String name = preset_settings[i+0];
  1350. String pname=preset_settings[i+1];
  1351. String deps=preset_settings[i+2];
  1352. int idx=1;
  1353. if (pname=="") {
  1354. pname="copy";
  1355. } else {
  1356. for(int j=0;j<names.size();j++) {
  1357. if (pname==names[j]) {
  1358. idx=j+2;
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. int dep_idx=0;
  1364. for(int j=0;j<ProjectExportSettings::DA_MAX;j++) {
  1365. if (ProjectExportSettings::da_string[j]==deps) {
  1366. dep_idx=j;
  1367. break;
  1368. }
  1369. }
  1370. if (idx>=0) {
  1371. export_action[name].action=idx;
  1372. export_action[name].depaction=dep_idx;
  1373. }
  1374. }
  1375. Set<String> bundle_exceptions;
  1376. for (Map<String,ProjectExportSettings::ItemData>::Element *E=export_action.front();E;E=E->next()) {
  1377. bundle_exceptions.insert(E->key());
  1378. }
  1379. {
  1380. // find dependencies and add them to export
  1381. Map<String,ProjectExportSettings::ItemData> dependencies;
  1382. for (Map<String,ProjectExportSettings::ItemData>::Element *E=export_action.front();E;E=E->next()) {
  1383. ProjectExportSettings::ItemData &id=E->get();
  1384. if (id.depaction!=ProjectExportSettings::DA_COPY && id.depaction!=ProjectExportSettings::DA_OPTIMIZE)
  1385. continue; //no copy or optimize, go on
  1386. List<String> deplist;
  1387. ResourceLoader::get_dependencies(E->key(),&deplist);
  1388. while (deplist.size()) {
  1389. String dependency = deplist.front()->get();
  1390. deplist.pop_front();
  1391. if (export_action.has(dependency))
  1392. continue; //taged to export, will not override
  1393. if (dependencies.has(dependency)) {
  1394. if (id.action <= dependencies[dependency].action )
  1395. continue;
  1396. }
  1397. ProjectExportSettings::ItemData depid;
  1398. if (id.depaction==ProjectExportSettings::DA_COPY || id.action==ProjectExportSettings::DA_COPY)
  1399. depid.action=ProjectExportSettings::DA_COPY;
  1400. else if (id.depaction==ProjectExportSettings::DA_OPTIMIZE)
  1401. depid.action=id.action;
  1402. depid.depaction=0;
  1403. dependencies[dependency]=depid;
  1404. ResourceLoader::get_dependencies(dependency,&deplist);
  1405. }
  1406. }
  1407. for (Map<String,ProjectExportSettings::ItemData>::Element *E=dependencies.front();E;E=E->next()) {
  1408. export_action[E->key()]=E->get();
  1409. }
  1410. }
  1411. int idx=0;
  1412. for (Map<String,ProjectExportSettings::ItemData>::Element *E=export_action.front();E;E=E->next(),idx++) {
  1413. String path=E->key();
  1414. if (E->get().action==0)
  1415. continue; //nothing to do here
  1416. String preset;
  1417. if (E->get().action==1)
  1418. preset="";
  1419. else
  1420. preset=names[E->get().action-2];
  1421. print_line("Exporting "+itos(idx)+"/"+itos(export_action.size())+": "+path);
  1422. String base_dir = Globals::get_singleton()->localize_path(path.get_base_dir()).replace("\\","/").replace("res://","");
  1423. DirAccess *da=DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
  1424. String cwd = d->get_current_dir();
  1425. da->change_dir(cwd);
  1426. print_line("base dir: "+base_dir);
  1427. String remap_platform="all";
  1428. for(int j=0;j<base_dir.get_slice_count("/");j++) {
  1429. String p = base_dir.get_slice("/",j);
  1430. if (da->change_dir(p)!=OK) {
  1431. Error err = da->make_dir(p);
  1432. if (err!=OK) {
  1433. memdelete(da);
  1434. memdelete(d);
  1435. ERR_EXPLAIN("Cannot make dir: "+cwd+"/"+p);
  1436. ERR_FAIL_V(ERR_CANT_CREATE);
  1437. }
  1438. if (da->change_dir(p)!=OK) {
  1439. memdelete(da);
  1440. memdelete(d);
  1441. ERR_EXPLAIN("Cannot change to dir: "+cwd+"/"+p);
  1442. ERR_FAIL_V(ERR_CANT_CREATE);
  1443. }
  1444. }
  1445. cwd=da->get_current_dir();
  1446. }
  1447. memdelete(da);
  1448. //cwd is the target dir
  1449. String source_file;
  1450. print_line("Exporting: "+source_file);
  1451. bool delete_source=false;
  1452. if (preset=="") {
  1453. //just copy!
  1454. source_file=path;
  1455. delete_source=false;
  1456. } else {
  1457. delete_source=true;
  1458. //create an optimized source file
  1459. if (!Globals::get_singleton()->has("optimizer_presets/"+preset)) {
  1460. memdelete(d);
  1461. ERR_EXPLAIN("Unknown optimizer preset: "+preset);
  1462. ERR_FAIL_V(ERR_INVALID_DATA);
  1463. }
  1464. Dictionary dc = Globals::get_singleton()->get("optimizer_presets/"+preset);
  1465. ERR_FAIL_COND_V(!dc.has("__type__"),ERR_INVALID_DATA);
  1466. String type=dc["__type__"];
  1467. Ref<EditorOptimizedSaver> saver;
  1468. for(int i=0;i<editor_data->get_optimized_saver_count();i++) {
  1469. if (editor_data->get_optimized_saver(i)->get_target_name()==type) {
  1470. saver=editor_data->get_optimized_saver(i);
  1471. }
  1472. }
  1473. if (saver.is_null()) {
  1474. memdelete(d);
  1475. ERR_EXPLAIN("Preset '"+preset+"' references nonexistent saver: "+type);
  1476. ERR_FAIL_COND_V(saver.is_null(),ERR_INVALID_DATA);
  1477. }
  1478. List<Variant> keys;
  1479. dc.get_key_list(&keys);
  1480. saver->clear();
  1481. for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
  1482. saver->set(E->get(),dc[E->get()]);
  1483. }
  1484. remap_platform=saver->get_target_platform();
  1485. if (remap_platform=="")
  1486. remap_platform="all";
  1487. if (resource_extensions.has(path.extension().to_lower())) {
  1488. uint32_t flags=0;
  1489. // if (saver->is_bundle_scenes_enabled())
  1490. // flags|=Reso::FLAG_BUNDLE_INSTANCED_SCENES;
  1491. saver->set_bundle_exceptions(NULL);
  1492. if (E->get().depaction>=ProjectExportSettings::DA_BUNDLE) {
  1493. flags|=ResourceSaver::FLAG_BUNDLE_RESOURCES;
  1494. if (E->get().depaction==ProjectExportSettings::DA_BUNDLE)
  1495. saver->set_bundle_exceptions(&bundle_exceptions);
  1496. }
  1497. if (saver->is_remove_editor_data_enabled())
  1498. flags|=ResourceSaver::FLAG_OMIT_EDITOR_PROPERTIES;
  1499. if (saver->is_big_endian_data_enabled())
  1500. flags|=ResourceSaver::FLAG_SAVE_BIG_ENDIAN;
  1501. RES res = ResourceLoader::load(path);
  1502. if (res.is_null()) {
  1503. memdelete(d);
  1504. ERR_EXPLAIN("Error loading resource to optimize: "+path);
  1505. ERR_FAIL_V(ERR_INVALID_DATA);
  1506. }
  1507. if (saver->is_compress_translations_enabled() && res->get_type()=="Translation") {
  1508. Ref<PHashTranslation> ct = Ref<PHashTranslation>( memnew( PHashTranslation ) );
  1509. ct->generate(res);
  1510. res=ct;
  1511. }
  1512. //dst_file=path.get_file();
  1513. //dst_file = cwd+"/"+dst_file.substr(0,dst_file.length()-dst_file.extension().length())+"opt.scn";
  1514. //String write_file = path.substr(0,path.length()-path.extension().length())+"optimized.res";
  1515. String write_file = path+".opt.res";
  1516. print_line("DST RES FILE: "+write_file);
  1517. Error err = ResourceSaver::save(write_file,res,flags,saver);
  1518. if (err) {
  1519. memdelete(d);
  1520. ERR_EXPLAIN("Error saving optimized resource: "+write_file);
  1521. ERR_FAIL_COND_V(err,ERR_CANT_OPEN);
  1522. }
  1523. source_file=write_file;
  1524. // project_settings->add_remapped_path(src_scene,path,platform);
  1525. }
  1526. }
  1527. String dst_file;
  1528. dst_file=cwd+"/"+source_file.get_file();
  1529. print_line("copying from: "+source_file);
  1530. print_line("copying to: "+dst_file);
  1531. Error err = d->copy(source_file,dst_file);
  1532. if (delete_source)
  1533. d->remove(source_file);
  1534. if (err) {
  1535. ERR_EXPLAIN("Error copying from: "+source_file+" to "+dst_file+".");
  1536. ERR_FAIL_COND_V(err,err);
  1537. }
  1538. String src_remap=path;
  1539. String dst_remap=source_file;
  1540. print_line("remap from: "+src_remap);
  1541. print_line("remap to: "+dst_remap);
  1542. if (src_remap!=dst_remap) {
  1543. remapped_paths[remap_platform][src_remap]=dst_remap;
  1544. }
  1545. //do the copy man...
  1546. }
  1547. Map<String,Variant> added_settings;
  1548. for (Map<String,Map<String,String> >::Element *E=remapped_paths.front();E;E=E->next()) {
  1549. String platform=E->key();
  1550. DVector<String> remaps;
  1551. for(Map<String,String>::Element *F=E->get().front();F;F=F->next() ) {
  1552. remaps.push_back(F->key());
  1553. remaps.push_back(F->get());
  1554. }
  1555. // added_settings["remap/"+platform]=remaps;`
  1556. added_settings["remap/"+platform]=Variant(remaps).operator Array();
  1557. }
  1558. String engine_cfg_path=d->get_current_dir()+"/engine.cfg";
  1559. print_line("enginecfg: "+engine_cfg_path);
  1560. Globals::get_singleton()->save_custom(engine_cfg_path,added_settings);
  1561. memdelete(d);
  1562. return OK;
  1563. #endif
  1564. }
  1565. ProjectExport::ProjectExport(EditorData *p_data) {
  1566. editor_data = p_data;
  1567. VBoxContainer *vbc = memnew(VBoxContainer);
  1568. add_child(vbc);
  1569. set_child_rect(vbc);
  1570. set_title(TTR("Project Export"));
  1571. label = memnew(Label);
  1572. label->set_text(TTR("Export Preset:"));
  1573. vbc->add_child(label);
  1574. export_preset = memnew(OptionButton);
  1575. vbc->add_child(export_preset);
  1576. get_ok()->set_text(TTR("Export"));
  1577. set_hide_on_ok(false);
  1578. error = memnew(AcceptDialog);
  1579. add_child(error);
  1580. }