project_export.cpp 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998
  1. /*************************************************************************/
  2. /* project_export.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "project_export.h"
  31. #include "compressed_translation.h"
  32. #include "editor_data.h"
  33. #include "editor_node.h"
  34. #include "editor_settings.h"
  35. #include "io/image_loader.h"
  36. #include "io/resource_loader.h"
  37. #include "io/resource_saver.h"
  38. #include "os/dir_access.h"
  39. #include "os/file_access.h"
  40. #include "os/os.h"
  41. #include "project_settings.h"
  42. #include "scene/gui/box_container.h"
  43. #include "scene/gui/margin_container.h"
  44. #include "scene/gui/scroll_container.h"
  45. #include "scene/gui/tab_container.h"
  46. void ProjectExportDialog::_notification(int p_what) {
  47. switch (p_what) {
  48. case NOTIFICATION_READY: {
  49. delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
  50. connect("confirmed", this, "_export_pck_zip");
  51. custom_feature_display->get_parent_control()->add_style_override("panel", get_stylebox("bg", "Tree"));
  52. } break;
  53. case NOTIFICATION_POPUP_HIDE: {
  54. EditorSettings::get_singleton()->set("interface/dialogs/export_bounds", get_rect());
  55. } break;
  56. }
  57. }
  58. void ProjectExportDialog::popup_export() {
  59. add_preset->get_popup()->clear();
  60. for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
  61. Ref<EditorExportPlatform> plat = EditorExport::get_singleton()->get_export_platform(i);
  62. add_preset->get_popup()->add_icon_item(plat->get_logo(), plat->get_name());
  63. }
  64. _update_presets();
  65. if (presets->get_current() >= 0) {
  66. _edit_preset(presets->get_current()); // triggers rescan for templates if newly installed
  67. }
  68. // Restore valid window bounds or pop up at default size.
  69. if (EditorSettings::get_singleton()->has_setting("interface/dialogs/export_bounds")) {
  70. popup(EditorSettings::get_singleton()->get("interface/dialogs/export_bounds"));
  71. } else {
  72. popup_centered_ratio();
  73. }
  74. }
  75. void ProjectExportDialog::_add_preset(int p_platform) {
  76. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_platform(p_platform)->create_preset();
  77. ERR_FAIL_COND(!preset.is_valid());
  78. String name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name();
  79. bool make_runnable = true;
  80. int attempt = 1;
  81. while (true) {
  82. bool valid = true;
  83. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  84. Ref<EditorExportPreset> p = EditorExport::get_singleton()->get_export_preset(i);
  85. if (p->get_platform() == preset->get_platform() && p->is_runnable()) {
  86. make_runnable = false;
  87. }
  88. if (p->get_name() == name) {
  89. valid = false;
  90. break;
  91. }
  92. }
  93. if (valid)
  94. break;
  95. attempt++;
  96. name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name() + " " + itos(attempt);
  97. }
  98. preset->set_name(name);
  99. if (make_runnable)
  100. preset->set_runnable(make_runnable);
  101. EditorExport::get_singleton()->add_export_preset(preset);
  102. _update_presets();
  103. _edit_preset(EditorExport::get_singleton()->get_export_preset_count() - 1);
  104. }
  105. void ProjectExportDialog::_update_presets() {
  106. updating = true;
  107. Ref<EditorExportPreset> current;
  108. if (presets->get_current() >= 0 && presets->get_current() < presets->get_item_count())
  109. current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  110. int current_idx = -1;
  111. presets->clear();
  112. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  113. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
  114. if (preset == current) {
  115. current_idx = i;
  116. }
  117. String name = preset->get_name();
  118. if (preset->is_runnable())
  119. name += " (" + TTR("Runnable") + ")";
  120. presets->add_item(name, preset->get_platform()->get_logo());
  121. }
  122. if (current_idx != -1) {
  123. presets->select(current_idx);
  124. }
  125. updating = false;
  126. }
  127. void ProjectExportDialog::_edit_preset(int p_index) {
  128. if (p_index < 0 || p_index >= presets->get_item_count()) {
  129. name->set_text("");
  130. name->set_editable(false);
  131. runnable->set_disabled(true);
  132. parameters->edit(NULL);
  133. presets->unselect_all();
  134. delete_preset->set_disabled(true);
  135. sections->hide();
  136. patches->clear();
  137. export_error->hide();
  138. export_templates_error->hide();
  139. return;
  140. }
  141. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(p_index);
  142. ERR_FAIL_COND(current.is_null());
  143. updating = true;
  144. presets->select(p_index);
  145. sections->show();
  146. name->set_editable(true);
  147. delete_preset->set_disabled(false);
  148. name->set_text(current->get_name());
  149. runnable->set_disabled(false);
  150. runnable->set_pressed(current->is_runnable());
  151. parameters->edit(current.ptr());
  152. export_filter->select(current->get_export_filter());
  153. include_filters->set_text(current->get_include_filter());
  154. exclude_filters->set_text(current->get_exclude_filter());
  155. patches->clear();
  156. TreeItem *patch_root = patches->create_item();
  157. Vector<String> patchlist = current->get_patches();
  158. for (int i = 0; i < patchlist.size(); i++) {
  159. TreeItem *patch = patches->create_item(patch_root);
  160. patch->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  161. String file = patchlist[i].get_file();
  162. patch->set_editable(0, true);
  163. patch->set_text(0, file.get_file().replace("*", ""));
  164. if (file.ends_with("*"))
  165. patch->set_checked(0, true);
  166. patch->set_tooltip(0, patchlist[i]);
  167. patch->set_metadata(0, i);
  168. patch->add_button(0, get_icon("Remove", "EditorIcons"), 0);
  169. patch->add_button(0, get_icon("folder", "FileDialog"), 1);
  170. }
  171. TreeItem *patch_add = patches->create_item(patch_root);
  172. patch_add->set_metadata(0, patchlist.size());
  173. if (patchlist.size() == 0)
  174. patch_add->set_text(0, "Add initial export...");
  175. else
  176. patch_add->set_text(0, "Add previous patches...");
  177. patch_add->add_button(0, get_icon("folder", "FileDialog"), 1);
  178. _fill_resource_tree();
  179. bool needs_templates;
  180. String error;
  181. if (!current->get_platform()->can_export(current, error, needs_templates)) {
  182. if (error != String()) {
  183. Vector<String> items = error.split("\n", false);
  184. error = "";
  185. for (int i = 0; i < items.size(); i++) {
  186. if (i > 0)
  187. error += "\n";
  188. error += " - " + items[i];
  189. }
  190. export_error->set_text(error);
  191. export_error->show();
  192. } else {
  193. export_error->hide();
  194. }
  195. if (needs_templates)
  196. export_templates_error->show();
  197. else
  198. export_templates_error->hide();
  199. export_button->set_disabled(true);
  200. } else {
  201. export_error->hide();
  202. export_templates_error->hide();
  203. export_button->set_disabled(false);
  204. }
  205. custom_features->set_text(current->get_custom_features());
  206. _update_feature_list();
  207. updating = false;
  208. }
  209. void ProjectExportDialog::_update_feature_list() {
  210. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  211. ERR_FAIL_COND(current.is_null());
  212. Set<String> fset;
  213. List<String> features;
  214. current->get_platform()->get_platform_features(&features);
  215. current->get_platform()->get_preset_features(current, &features);
  216. String custom = current->get_custom_features();
  217. Vector<String> custom_list = custom.split(",");
  218. for (int i = 0; i < custom_list.size(); i++) {
  219. String f = custom_list[i].strip_edges();
  220. if (f != String()) {
  221. features.push_back(f);
  222. }
  223. }
  224. for (List<String>::Element *E = features.front(); E; E = E->next()) {
  225. fset.insert(E->get());
  226. }
  227. custom_feature_display->clear();
  228. for (Set<String>::Element *E = fset.front(); E; E = E->next()) {
  229. String f = E->get();
  230. if (E->next()) {
  231. f += ", ";
  232. }
  233. custom_feature_display->add_text(f);
  234. }
  235. }
  236. void ProjectExportDialog::_custom_features_changed(const String &p_text) {
  237. if (updating)
  238. return;
  239. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  240. ERR_FAIL_COND(current.is_null());
  241. current->set_custom_features(p_text);
  242. _update_feature_list();
  243. }
  244. void ProjectExportDialog::_tab_changed(int) {
  245. _update_feature_list();
  246. }
  247. void ProjectExportDialog::_patch_button_pressed(Object *p_item, int p_column, int p_id) {
  248. TreeItem *ti = (TreeItem *)p_item;
  249. patch_index = ti->get_metadata(0);
  250. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  251. ERR_FAIL_COND(current.is_null());
  252. if (p_id == 0) {
  253. Vector<String> patches = current->get_patches();
  254. ERR_FAIL_INDEX(patch_index, patches.size());
  255. patch_erase->set_text(vformat(TTR("Delete patch '%s' from list?"), patches[patch_index].get_file()));
  256. patch_erase->popup_centered_minsize();
  257. } else {
  258. patch_dialog->popup_centered_ratio();
  259. }
  260. }
  261. void ProjectExportDialog::_patch_edited() {
  262. TreeItem *item = patches->get_edited();
  263. if (!item)
  264. return;
  265. int index = item->get_metadata(0);
  266. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  267. ERR_FAIL_COND(current.is_null());
  268. Vector<String> patches = current->get_patches();
  269. ERR_FAIL_INDEX(index, patches.size());
  270. String patch = patches[index].replace("*", "");
  271. if (item->is_checked(0)) {
  272. patch += "*";
  273. }
  274. current->set_patch(index, patch);
  275. }
  276. void ProjectExportDialog::_patch_selected(const String &p_path) {
  277. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  278. ERR_FAIL_COND(current.is_null());
  279. Vector<String> patches = current->get_patches();
  280. if (patch_index >= patches.size()) {
  281. current->add_patch(ProjectSettings::get_singleton()->get_resource_path().path_to(p_path) + "*");
  282. } else {
  283. String enabled = patches[patch_index].ends_with("*") ? String("*") : String();
  284. current->set_patch(patch_index, ProjectSettings::get_singleton()->get_resource_path().path_to(p_path) + enabled);
  285. }
  286. _edit_preset(presets->get_current());
  287. }
  288. void ProjectExportDialog::_patch_deleted() {
  289. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  290. ERR_FAIL_COND(current.is_null());
  291. Vector<String> patches = current->get_patches();
  292. if (patch_index < patches.size()) {
  293. current->remove_patch(patch_index);
  294. _edit_preset(presets->get_current());
  295. }
  296. }
  297. void ProjectExportDialog::_update_parameters(const String &p_edited_property) {
  298. _edit_preset(presets->get_current());
  299. parameters->update_tree();
  300. }
  301. void ProjectExportDialog::_runnable_pressed() {
  302. if (updating)
  303. return;
  304. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  305. ERR_FAIL_COND(current.is_null());
  306. if (runnable->is_pressed()) {
  307. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  308. Ref<EditorExportPreset> p = EditorExport::get_singleton()->get_export_preset(i);
  309. if (p->get_platform() == current->get_platform()) {
  310. p->set_runnable(current == p);
  311. }
  312. }
  313. } else {
  314. current->set_runnable(false);
  315. }
  316. _update_presets();
  317. }
  318. void ProjectExportDialog::_name_changed(const String &p_string) {
  319. if (updating)
  320. return;
  321. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  322. ERR_FAIL_COND(current.is_null());
  323. current->set_name(p_string);
  324. _update_presets();
  325. }
  326. void ProjectExportDialog::_delete_preset() {
  327. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  328. if (current.is_null())
  329. return;
  330. delete_confirm->set_text(vformat(TTR("Delete preset '%s'?"), current->get_name()));
  331. delete_confirm->popup_centered_minsize();
  332. }
  333. void ProjectExportDialog::_delete_preset_confirm() {
  334. int idx = presets->get_current();
  335. _edit_preset(-1);
  336. EditorExport::get_singleton()->remove_export_preset(idx);
  337. _update_presets();
  338. }
  339. Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
  340. if (p_from == presets) {
  341. int pos = presets->get_item_at_position(p_point, true);
  342. if (pos >= 0) {
  343. Dictionary d;
  344. d["type"] = "export_preset";
  345. d["preset"] = pos;
  346. HBoxContainer *drag = memnew(HBoxContainer);
  347. TextureRect *tr = memnew(TextureRect);
  348. tr->set_texture(presets->get_item_icon(pos));
  349. drag->add_child(tr);
  350. Label *label = memnew(Label);
  351. label->set_text(presets->get_item_text(pos));
  352. drag->add_child(label);
  353. set_drag_preview(drag);
  354. return d;
  355. }
  356. } else if (p_from == patches) {
  357. TreeItem *item = patches->get_item_at_position(p_point);
  358. if (item && item->get_cell_mode(0) == TreeItem::CELL_MODE_CHECK) {
  359. int metadata = item->get_metadata(0);
  360. Dictionary d;
  361. d["type"] = "export_patch";
  362. d["patch"] = metadata;
  363. Label *label = memnew(Label);
  364. label->set_text(item->get_text(0));
  365. set_drag_preview(label);
  366. return d;
  367. }
  368. }
  369. return Variant();
  370. }
  371. bool ProjectExportDialog::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
  372. if (p_from == presets) {
  373. Dictionary d = p_data;
  374. if (!d.has("type") || String(d["type"]) != "export_preset")
  375. return false;
  376. if (presets->get_item_at_position(p_point, true) < 0 && !presets->is_pos_at_end_of_items(p_point))
  377. return false;
  378. } else if (p_from == patches) {
  379. Dictionary d = p_data;
  380. if (!d.has("type") || String(d["type"]) != "export_patch")
  381. return false;
  382. patches->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM);
  383. TreeItem *item = patches->get_item_at_position(p_point);
  384. if (!item) {
  385. return false;
  386. }
  387. }
  388. return true;
  389. }
  390. void ProjectExportDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
  391. if (p_from == presets) {
  392. Dictionary d = p_data;
  393. int from_pos = d["preset"];
  394. int to_pos = -1;
  395. if (presets->get_item_at_position(p_point, true) >= 0) {
  396. to_pos = presets->get_item_at_position(p_point, true);
  397. }
  398. if (to_pos == -1 && !presets->is_pos_at_end_of_items(p_point))
  399. return;
  400. if (to_pos == from_pos)
  401. return;
  402. else if (to_pos > from_pos) {
  403. to_pos--;
  404. }
  405. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(from_pos);
  406. EditorExport::get_singleton()->remove_export_preset(from_pos);
  407. EditorExport::get_singleton()->add_export_preset(preset, to_pos);
  408. _update_presets();
  409. if (to_pos >= 0)
  410. _edit_preset(to_pos);
  411. else
  412. _edit_preset(presets->get_item_count() - 1);
  413. } else if (p_from == patches) {
  414. Dictionary d = p_data;
  415. if (!d.has("type") || String(d["type"]) != "export_patch")
  416. return;
  417. int from_pos = d["patch"];
  418. TreeItem *item = patches->get_item_at_position(p_point);
  419. if (!item)
  420. return;
  421. int to_pos = item->get_cell_mode(0) == TreeItem::CELL_MODE_CHECK ? int(item->get_metadata(0)) : -1;
  422. if (to_pos == from_pos)
  423. return;
  424. else if (to_pos > from_pos) {
  425. to_pos--;
  426. }
  427. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  428. String patch = preset->get_patch(from_pos);
  429. preset->remove_patch(from_pos);
  430. preset->add_patch(patch, to_pos);
  431. _edit_preset(presets->get_current());
  432. }
  433. }
  434. void ProjectExportDialog::_export_type_changed(int p_which) {
  435. if (updating)
  436. return;
  437. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  438. if (current.is_null())
  439. return;
  440. current->set_export_filter(EditorExportPreset::ExportFilter(p_which));
  441. updating = true;
  442. _fill_resource_tree();
  443. updating = false;
  444. }
  445. void ProjectExportDialog::_filter_changed(const String &p_filter) {
  446. if (updating)
  447. return;
  448. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  449. if (current.is_null())
  450. return;
  451. current->set_include_filter(include_filters->get_text());
  452. current->set_exclude_filter(exclude_filters->get_text());
  453. }
  454. void ProjectExportDialog::_fill_resource_tree() {
  455. include_files->clear();
  456. include_label->hide();
  457. include_margin->hide();
  458. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  459. if (current.is_null())
  460. return;
  461. EditorExportPreset::ExportFilter f = current->get_export_filter();
  462. if (f == EditorExportPreset::EXPORT_ALL_RESOURCES) {
  463. return;
  464. }
  465. include_label->show();
  466. include_margin->show();
  467. TreeItem *root = include_files->create_item();
  468. _fill_tree(EditorFileSystem::get_singleton()->get_filesystem(), root, current, f == EditorExportPreset::EXPORT_SELECTED_SCENES);
  469. }
  470. bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref<EditorExportPreset> &current, bool p_only_scenes) {
  471. p_item->set_icon(0, get_icon("folder", "FileDialog"));
  472. p_item->set_text(0, p_dir->get_name() + "/");
  473. bool used = false;
  474. for (int i = 0; i < p_dir->get_subdir_count(); i++) {
  475. TreeItem *subdir = include_files->create_item(p_item);
  476. if (_fill_tree(p_dir->get_subdir(i), subdir, current, p_only_scenes) == false) {
  477. memdelete(subdir);
  478. } else {
  479. used = true;
  480. }
  481. }
  482. for (int i = 0; i < p_dir->get_file_count(); i++) {
  483. String type = p_dir->get_file_type(i);
  484. if (p_only_scenes && type != "PackedScene")
  485. continue;
  486. TreeItem *file = include_files->create_item(p_item);
  487. file->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  488. file->set_text(0, p_dir->get_file(i));
  489. Ref<Texture> tex;
  490. if (has_icon(type, editor_icons)) {
  491. tex = get_icon(type, editor_icons);
  492. } else {
  493. tex = get_icon("Object", editor_icons);
  494. }
  495. String path = p_dir->get_file_path(i);
  496. file->set_icon(0, tex);
  497. file->set_editable(0, true);
  498. file->set_checked(0, current->has_export_file(path));
  499. file->set_metadata(0, path);
  500. used = true;
  501. }
  502. return used;
  503. }
  504. void ProjectExportDialog::_tree_changed() {
  505. if (updating)
  506. return;
  507. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  508. if (current.is_null())
  509. return;
  510. TreeItem *item = include_files->get_edited();
  511. if (!item)
  512. return;
  513. String path = item->get_metadata(0);
  514. bool added = item->is_checked(0);
  515. if (added) {
  516. current->add_export_file(path);
  517. } else {
  518. current->remove_export_file(path);
  519. }
  520. }
  521. void ProjectExportDialog::_export_pck_zip() {
  522. export_pck_zip->popup_centered_ratio();
  523. }
  524. void ProjectExportDialog::_export_pck_zip_selected(const String &p_path) {
  525. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  526. ERR_FAIL_COND(current.is_null());
  527. Ref<EditorExportPlatform> platform = current->get_platform();
  528. ERR_FAIL_COND(platform.is_null());
  529. if (p_path.ends_with(".zip")) {
  530. platform->export_zip(current, export_pck_zip_debug->is_pressed(), p_path);
  531. } else if (p_path.ends_with(".pck")) {
  532. platform->export_pack(current, export_pck_zip_debug->is_pressed(), p_path);
  533. }
  534. }
  535. void ProjectExportDialog::_open_export_template_manager() {
  536. EditorNode::get_singleton()->open_export_template_manager();
  537. hide();
  538. }
  539. void ProjectExportDialog::_export_project() {
  540. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  541. ERR_FAIL_COND(current.is_null());
  542. Ref<EditorExportPlatform> platform = current->get_platform();
  543. ERR_FAIL_COND(platform.is_null());
  544. export_project->set_access(FileDialog::ACCESS_FILESYSTEM);
  545. export_project->clear_filters();
  546. export_project->set_current_file(default_filename);
  547. String extension = platform->get_binary_extension(current);
  548. if (extension != String()) {
  549. export_project->add_filter("*." + extension + " ; " + platform->get_name() + " Export");
  550. }
  551. export_project->set_mode(FileDialog::MODE_SAVE_FILE);
  552. export_project->popup_centered_ratio();
  553. }
  554. void ProjectExportDialog::_export_project_to_path(const String &p_path) {
  555. // Save this name for use in future exports (but drop the file extension)
  556. default_filename = p_path.get_basename().get_file();
  557. EditorSettings::get_singleton()->set_project_metadata("export_options", "default_filename", default_filename);
  558. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(presets->get_current());
  559. ERR_FAIL_COND(current.is_null());
  560. Ref<EditorExportPlatform> platform = current->get_platform();
  561. ERR_FAIL_COND(platform.is_null());
  562. Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
  563. if (err != OK) {
  564. error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " " + platform->get_name());
  565. error_dialog->show();
  566. error_dialog->popup_centered_minsize(Size2(300, 80));
  567. ERR_PRINT("Failed to export project");
  568. }
  569. }
  570. void ProjectExportDialog::_bind_methods() {
  571. ClassDB::bind_method("_add_preset", &ProjectExportDialog::_add_preset);
  572. ClassDB::bind_method("_edit_preset", &ProjectExportDialog::_edit_preset);
  573. ClassDB::bind_method("_update_parameters", &ProjectExportDialog::_update_parameters);
  574. ClassDB::bind_method("_runnable_pressed", &ProjectExportDialog::_runnable_pressed);
  575. ClassDB::bind_method("_name_changed", &ProjectExportDialog::_name_changed);
  576. ClassDB::bind_method("_delete_preset", &ProjectExportDialog::_delete_preset);
  577. ClassDB::bind_method("_delete_preset_confirm", &ProjectExportDialog::_delete_preset_confirm);
  578. ClassDB::bind_method("get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
  579. ClassDB::bind_method("can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw);
  580. ClassDB::bind_method("drop_data_fw", &ProjectExportDialog::drop_data_fw);
  581. ClassDB::bind_method("_export_type_changed", &ProjectExportDialog::_export_type_changed);
  582. ClassDB::bind_method("_filter_changed", &ProjectExportDialog::_filter_changed);
  583. ClassDB::bind_method("_tree_changed", &ProjectExportDialog::_tree_changed);
  584. ClassDB::bind_method("_patch_button_pressed", &ProjectExportDialog::_patch_button_pressed);
  585. ClassDB::bind_method("_patch_selected", &ProjectExportDialog::_patch_selected);
  586. ClassDB::bind_method("_patch_deleted", &ProjectExportDialog::_patch_deleted);
  587. ClassDB::bind_method("_patch_edited", &ProjectExportDialog::_patch_edited);
  588. ClassDB::bind_method("_export_pck_zip", &ProjectExportDialog::_export_pck_zip);
  589. ClassDB::bind_method("_export_pck_zip_selected", &ProjectExportDialog::_export_pck_zip_selected);
  590. ClassDB::bind_method("_open_export_template_manager", &ProjectExportDialog::_open_export_template_manager);
  591. ClassDB::bind_method("_export_project", &ProjectExportDialog::_export_project);
  592. ClassDB::bind_method("_export_project_to_path", &ProjectExportDialog::_export_project_to_path);
  593. ClassDB::bind_method("_custom_features_changed", &ProjectExportDialog::_custom_features_changed);
  594. ClassDB::bind_method("_tab_changed", &ProjectExportDialog::_tab_changed);
  595. }
  596. ProjectExportDialog::ProjectExportDialog() {
  597. set_title(TTR("Export"));
  598. set_resizable(true);
  599. VBoxContainer *main_vb = memnew(VBoxContainer);
  600. add_child(main_vb);
  601. HBoxContainer *hbox = memnew(HBoxContainer);
  602. main_vb->add_child(hbox);
  603. hbox->set_v_size_flags(SIZE_EXPAND_FILL);
  604. VBoxContainer *preset_vb = memnew(VBoxContainer);
  605. preset_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  606. hbox->add_child(preset_vb);
  607. HBoxContainer *preset_hb = memnew(HBoxContainer);
  608. preset_hb->add_child(memnew(Label(TTR("Presets"))));
  609. preset_hb->add_spacer();
  610. preset_vb->add_child(preset_hb);
  611. add_preset = memnew(MenuButton);
  612. add_preset->set_text(TTR("Add..."));
  613. add_preset->get_popup()->connect("index_pressed", this, "_add_preset");
  614. preset_hb->add_child(add_preset);
  615. MarginContainer *mc = memnew(MarginContainer);
  616. preset_vb->add_child(mc);
  617. mc->set_v_size_flags(SIZE_EXPAND_FILL);
  618. presets = memnew(ItemList);
  619. presets->set_drag_forwarding(this);
  620. mc->add_child(presets);
  621. presets->connect("item_selected", this, "_edit_preset");
  622. delete_preset = memnew(ToolButton);
  623. preset_hb->add_child(delete_preset);
  624. delete_preset->connect("pressed", this, "_delete_preset");
  625. VBoxContainer *settings_vb = memnew(VBoxContainer);
  626. settings_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  627. hbox->add_child(settings_vb);
  628. name = memnew(LineEdit);
  629. settings_vb->add_margin_child(TTR("Name:"), name);
  630. name->connect("text_changed", this, "_name_changed");
  631. runnable = memnew(CheckButton);
  632. runnable->set_text(TTR("Runnable"));
  633. runnable->connect("pressed", this, "_runnable_pressed");
  634. settings_vb->add_child(runnable);
  635. sections = memnew(TabContainer);
  636. sections->set_tab_align(TabContainer::ALIGN_LEFT);
  637. settings_vb->add_child(sections);
  638. sections->set_v_size_flags(SIZE_EXPAND_FILL);
  639. parameters = memnew(PropertyEditor);
  640. sections->add_child(parameters);
  641. parameters->set_name(TTR("Options"));
  642. parameters->hide_top_label();
  643. parameters->set_v_size_flags(SIZE_EXPAND_FILL);
  644. parameters->connect("property_edited", this, "_update_parameters");
  645. VBoxContainer *resources_vb = memnew(VBoxContainer);
  646. sections->add_child(resources_vb);
  647. resources_vb->set_name(TTR("Resources"));
  648. export_filter = memnew(OptionButton);
  649. export_filter->add_item(TTR("Export all resources in the project"));
  650. export_filter->add_item(TTR("Export selected scenes (and dependencies)"));
  651. export_filter->add_item(TTR("Export selected resources (and dependencies)"));
  652. resources_vb->add_margin_child(TTR("Export Mode:"), export_filter);
  653. export_filter->connect("item_selected", this, "_export_type_changed");
  654. include_label = memnew(Label);
  655. include_label->set_text(TTR("Resources to export:"));
  656. resources_vb->add_child(include_label);
  657. include_margin = memnew(MarginContainer);
  658. include_margin->set_v_size_flags(SIZE_EXPAND_FILL);
  659. resources_vb->add_child(include_margin);
  660. include_files = memnew(Tree);
  661. include_margin->add_child(include_files);
  662. include_files->connect("item_edited", this, "_tree_changed");
  663. include_filters = memnew(LineEdit);
  664. resources_vb->add_margin_child(TTR("Filters to export non-resource files (comma separated, e.g: *.json, *.txt)"), include_filters);
  665. include_filters->connect("text_changed", this, "_filter_changed");
  666. exclude_filters = memnew(LineEdit);
  667. resources_vb->add_margin_child(TTR("Filters to exclude files from project (comma separated, e.g: *.json, *.txt)"), exclude_filters);
  668. exclude_filters->connect("text_changed", this, "_filter_changed");
  669. VBoxContainer *patch_vb = memnew(VBoxContainer);
  670. sections->add_child(patch_vb);
  671. patch_vb->set_name(TTR("Patches"));
  672. patches = memnew(Tree);
  673. patch_vb->add_child(patches);
  674. patches->set_v_size_flags(SIZE_EXPAND_FILL);
  675. patches->set_hide_root(true);
  676. patches->connect("button_pressed", this, "_patch_button_pressed");
  677. patches->connect("item_edited", this, "_patch_edited");
  678. patches->set_drag_forwarding(this);
  679. patches->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
  680. HBoxContainer *patches_hb = memnew(HBoxContainer);
  681. patch_vb->add_child(patches_hb);
  682. patches_hb->add_spacer();
  683. patch_export = memnew(Button);
  684. patch_export->set_text(TTR("Make Patch"));
  685. patches_hb->add_child(patch_export);
  686. patches_hb->add_spacer();
  687. patch_dialog = memnew(FileDialog);
  688. patch_dialog->add_filter("*.pck ; Pack File");
  689. patch_dialog->set_mode(FileDialog::MODE_OPEN_FILE);
  690. patch_dialog->connect("file_selected", this, "_patch_selected");
  691. add_child(patch_dialog);
  692. patch_erase = memnew(ConfirmationDialog);
  693. patch_erase->get_ok()->set_text(TTR("Delete"));
  694. patch_erase->connect("confirmed", this, "_patch_deleted");
  695. add_child(patch_erase);
  696. VBoxContainer *feature_vb = memnew(VBoxContainer);
  697. feature_vb->set_name(TTR("Features"));
  698. custom_features = memnew(LineEdit);
  699. custom_features->connect("text_changed", this, "_custom_features_changed");
  700. feature_vb->add_margin_child(TTR("Custom (comma-separated):"), custom_features);
  701. Panel *features_panel = memnew(Panel);
  702. custom_feature_display = memnew(RichTextLabel);
  703. features_panel->add_child(custom_feature_display);
  704. custom_feature_display->set_anchors_and_margins_preset(Control::PRESET_WIDE, Control::PRESET_MODE_MINSIZE, 10 * EDSCALE);
  705. custom_feature_display->set_v_size_flags(SIZE_EXPAND_FILL);
  706. feature_vb->add_margin_child(TTR("Feature List:"), features_panel, true);
  707. sections->add_child(feature_vb);
  708. sections->connect("tab_changed", this, "_tab_changed");
  709. //disable by default
  710. name->set_editable(false);
  711. runnable->set_disabled(true);
  712. delete_preset->set_disabled(true);
  713. sections->hide();
  714. parameters->edit(NULL);
  715. delete_confirm = memnew(ConfirmationDialog);
  716. add_child(delete_confirm);
  717. delete_confirm->get_ok()->set_text(TTR("Delete"));
  718. delete_confirm->connect("confirmed", this, "_delete_preset_confirm");
  719. updating = false;
  720. get_cancel()->set_text(TTR("Close"));
  721. get_ok()->set_text(TTR("Export PCK/Zip"));
  722. export_button = add_button(TTR("Export Project"), !OS::get_singleton()->get_swap_ok_cancel(), "export");
  723. export_pck_zip = memnew(FileDialog);
  724. export_pck_zip->add_filter("*.zip ; ZIP File");
  725. export_pck_zip->add_filter("*.pck ; Godot Game Pack");
  726. export_pck_zip->set_access(FileDialog::ACCESS_FILESYSTEM);
  727. export_pck_zip->set_mode(FileDialog::MODE_SAVE_FILE);
  728. add_child(export_pck_zip);
  729. export_pck_zip->connect("file_selected", this, "_export_pck_zip_selected");
  730. export_error = memnew(Label);
  731. main_vb->add_child(export_error);
  732. export_error->hide();
  733. export_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
  734. export_templates_error = memnew(HBoxContainer);
  735. main_vb->add_child(export_templates_error);
  736. export_templates_error->hide();
  737. Label *export_error2 = memnew(Label);
  738. export_templates_error->add_child(export_error2);
  739. export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
  740. export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
  741. error_dialog = memnew(AcceptDialog);
  742. error_dialog->set_title("Error");
  743. error_dialog->set_text(TTR("Export templates for this platform are missing/corrupted:") + " ");
  744. main_vb->add_child(error_dialog);
  745. error_dialog->hide();
  746. LinkButton *download_templates = memnew(LinkButton);
  747. download_templates->set_text(TTR("Manage Export Templates"));
  748. download_templates->set_v_size_flags(SIZE_SHRINK_CENTER);
  749. export_templates_error->add_child(download_templates);
  750. download_templates->connect("pressed", this, "_open_export_template_manager");
  751. export_project = memnew(FileDialog);
  752. export_project->set_access(FileDialog::ACCESS_FILESYSTEM);
  753. add_child(export_project);
  754. export_project->connect("file_selected", this, "_export_project_to_path");
  755. export_button->connect("pressed", this, "_export_project");
  756. export_debug = memnew(CheckButton);
  757. export_debug->set_text(TTR("Export With Debug"));
  758. export_debug->set_pressed(true);
  759. export_project->get_vbox()->add_child(export_debug);
  760. export_pck_zip_debug = memnew(CheckButton);
  761. export_pck_zip_debug->set_text(TTR("Export With Debug"));
  762. export_pck_zip_debug->set_pressed(true);
  763. export_pck_zip->get_vbox()->add_child(export_pck_zip_debug);
  764. set_hide_on_ok(false);
  765. editor_icons = "EditorIcons";
  766. default_filename = EditorSettings::get_singleton()->get_project_metadata("export_options", "default_filename", String());
  767. if (default_filename == "") {
  768. default_filename = ProjectSettings::get_singleton()->get("application/config/name");
  769. }
  770. }
  771. ProjectExportDialog::~ProjectExportDialog() {
  772. }