project_export.cpp 41 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253
  1. /**************************************************************************/
  2. /* project_export.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  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 "core/compressed_translation.h"
  32. #include "core/io/image_loader.h"
  33. #include "core/io/resource_loader.h"
  34. #include "core/io/resource_saver.h"
  35. #include "core/os/dir_access.h"
  36. #include "core/os/file_access.h"
  37. #include "core/os/os.h"
  38. #include "core/project_settings.h"
  39. #include "core/version_generated.gen.h"
  40. #include "editor_data.h"
  41. #include "editor_node.h"
  42. #include "editor_scale.h"
  43. #include "editor_settings.h"
  44. #include "scene/gui/box_container.h"
  45. #include "scene/gui/margin_container.h"
  46. #include "scene/gui/scroll_container.h"
  47. #include "scene/gui/tab_container.h"
  48. void ProjectExportDialog::_notification(int p_what) {
  49. switch (p_what) {
  50. case NOTIFICATION_ENTER_TREE:
  51. case NOTIFICATION_THEME_CHANGED: {
  52. duplicate_preset->set_icon(get_icon("Duplicate", "EditorIcons"));
  53. delete_preset->set_icon(get_icon("Remove", "EditorIcons"));
  54. } break;
  55. case NOTIFICATION_READY: {
  56. connect("confirmed", this, "_export_pck_zip");
  57. _update_export_all();
  58. } break;
  59. case NOTIFICATION_POPUP_HIDE: {
  60. EditorSettings::get_singleton()->set_project_metadata("dialog_bounds", "export", get_rect());
  61. } break;
  62. case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
  63. parameters->set_property_name_style(EditorPropertyNameProcessor::get_settings_style());
  64. } break;
  65. }
  66. }
  67. void ProjectExportDialog::popup_export() {
  68. add_preset->get_popup()->clear();
  69. for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
  70. Ref<EditorExportPlatform> plat = EditorExport::get_singleton()->get_export_platform(i);
  71. add_preset->get_popup()->add_icon_item(plat->get_logo(), plat->get_name());
  72. }
  73. _update_presets();
  74. if (presets->get_current() >= 0) {
  75. _update_current_preset(); // triggers rescan for templates if newly installed
  76. }
  77. // Restore valid window bounds or pop up at default size.
  78. Rect2 saved_size = EditorSettings::get_singleton()->get_project_metadata("dialog_bounds", "export", Rect2());
  79. if (saved_size != Rect2()) {
  80. popup(saved_size);
  81. } else {
  82. popup_centered_clamped(Size2(900, 700) * EDSCALE, 0.8);
  83. }
  84. }
  85. void ProjectExportDialog::_add_preset(int p_platform) {
  86. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_platform(p_platform)->create_preset();
  87. ERR_FAIL_COND(!preset.is_valid());
  88. String name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name();
  89. bool make_runnable = true;
  90. int attempt = 1;
  91. while (true) {
  92. bool valid = true;
  93. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  94. Ref<EditorExportPreset> p = EditorExport::get_singleton()->get_export_preset(i);
  95. if (p->get_platform() == preset->get_platform() && p->is_runnable()) {
  96. make_runnable = false;
  97. }
  98. if (p->get_name() == name) {
  99. valid = false;
  100. break;
  101. }
  102. }
  103. if (valid) {
  104. break;
  105. }
  106. attempt++;
  107. name = EditorExport::get_singleton()->get_export_platform(p_platform)->get_name() + " " + itos(attempt);
  108. }
  109. preset->set_name(name);
  110. if (make_runnable) {
  111. preset->set_runnable(make_runnable);
  112. }
  113. EditorExport::get_singleton()->add_export_preset(preset);
  114. _update_presets();
  115. _edit_preset(EditorExport::get_singleton()->get_export_preset_count() - 1);
  116. }
  117. void ProjectExportDialog::_force_update_current_preset_parameters() {
  118. // Force the parameters section to refresh its UI.
  119. parameters->edit(nullptr);
  120. _update_current_preset();
  121. }
  122. void ProjectExportDialog::_update_current_preset() {
  123. _edit_preset(presets->get_current());
  124. }
  125. void ProjectExportDialog::_update_presets() {
  126. updating = true;
  127. Ref<EditorExportPreset> current;
  128. if (presets->get_current() >= 0 && presets->get_current() < presets->get_item_count()) {
  129. current = get_current_preset();
  130. }
  131. int current_idx = -1;
  132. presets->clear();
  133. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  134. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
  135. if (preset == current) {
  136. current_idx = i;
  137. }
  138. String name = preset->get_name();
  139. if (preset->is_runnable()) {
  140. name += " (" + TTR("Runnable") + ")";
  141. }
  142. preset->update_files_to_export();
  143. presets->add_item(name, preset->get_platform()->get_logo());
  144. }
  145. if (current_idx != -1) {
  146. presets->select(current_idx);
  147. }
  148. updating = false;
  149. }
  150. void ProjectExportDialog::_update_export_all() {
  151. bool can_export = EditorExport::get_singleton()->get_export_preset_count() > 0;
  152. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  153. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
  154. bool needs_templates;
  155. String error;
  156. if (preset->get_export_path() == "" || !preset->get_platform()->can_export(preset, error, needs_templates)) {
  157. can_export = false;
  158. break;
  159. }
  160. }
  161. export_all_button->set_disabled(!can_export);
  162. if (can_export) {
  163. export_all_button->set_tooltip(TTR("Export the project for all the presets defined."));
  164. } else {
  165. export_all_button->set_tooltip(TTR("All presets must have an export path defined for Export All to work."));
  166. }
  167. }
  168. void ProjectExportDialog::_edit_preset(int p_index) {
  169. if (p_index < 0 || p_index >= presets->get_item_count()) {
  170. name->set_text("");
  171. name->set_editable(false);
  172. export_path->hide();
  173. runnable->set_disabled(true);
  174. parameters->edit(nullptr);
  175. presets->unselect_all();
  176. duplicate_preset->set_disabled(true);
  177. delete_preset->set_disabled(true);
  178. sections->hide();
  179. export_error->hide();
  180. export_templates_error->hide();
  181. return;
  182. }
  183. Ref<EditorExportPreset> current = EditorExport::get_singleton()->get_export_preset(p_index);
  184. ERR_FAIL_COND(current.is_null());
  185. updating = true;
  186. presets->select(p_index);
  187. sections->show();
  188. name->set_editable(true);
  189. export_path->show();
  190. duplicate_preset->set_disabled(false);
  191. delete_preset->set_disabled(false);
  192. name->set_text(current->get_name());
  193. List<String> extension_list = current->get_platform()->get_binary_extensions(current);
  194. Vector<String> extension_vector;
  195. for (int i = 0; i < extension_list.size(); i++) {
  196. extension_vector.push_back("*." + extension_list[i]);
  197. }
  198. export_path->setup(extension_vector, false, true);
  199. export_path->update_property();
  200. runnable->set_disabled(false);
  201. runnable->set_pressed(current->is_runnable());
  202. parameters->edit(current.ptr());
  203. export_filter->select(current->get_export_filter());
  204. include_filters->set_text(current->get_include_filter());
  205. exclude_filters->set_text(current->get_exclude_filter());
  206. _fill_resource_tree();
  207. bool needs_templates;
  208. String error;
  209. if (!current->get_platform()->can_export(current, error, needs_templates)) {
  210. if (error != String()) {
  211. Vector<String> items = error.split("\n", false);
  212. error = "";
  213. for (int i = 0; i < items.size(); i++) {
  214. if (i > 0) {
  215. error += "\n";
  216. }
  217. error += " - " + items[i];
  218. }
  219. export_error->set_text(error);
  220. export_error->show();
  221. } else {
  222. export_error->hide();
  223. }
  224. export_warning->hide();
  225. if (needs_templates) {
  226. export_templates_error->show();
  227. } else {
  228. export_templates_error->hide();
  229. }
  230. export_button->set_disabled(true);
  231. get_ok()->set_disabled(true);
  232. } else {
  233. if (error != String()) {
  234. Vector<String> items = error.split("\n", false);
  235. error = "";
  236. for (int i = 0; i < items.size(); i++) {
  237. if (i > 0) {
  238. error += "\n";
  239. }
  240. error += " - " + items[i];
  241. }
  242. export_warning->set_text(error);
  243. export_warning->show();
  244. } else {
  245. export_warning->hide();
  246. }
  247. export_error->hide();
  248. export_templates_error->hide();
  249. export_button->set_disabled(false);
  250. get_ok()->set_disabled(false);
  251. }
  252. custom_features->set_text(current->get_custom_features());
  253. _update_feature_list();
  254. _update_export_all();
  255. minimum_size_changed();
  256. int script_export_mode = current->get_script_export_mode();
  257. script_mode->select(script_export_mode);
  258. String key = current->get_script_encryption_key();
  259. if (!updating_script_key) {
  260. script_key->set_text(key);
  261. }
  262. if (script_export_mode == EditorExportPreset::MODE_SCRIPT_ENCRYPTED) {
  263. script_key->set_editable(true);
  264. bool key_valid = _validate_script_encryption_key(key);
  265. if (key_valid) {
  266. script_key_error->hide();
  267. } else {
  268. script_key_error->show();
  269. }
  270. } else {
  271. script_key->set_editable(false);
  272. script_key_error->hide();
  273. }
  274. updating = false;
  275. }
  276. void ProjectExportDialog::_update_feature_list() {
  277. Ref<EditorExportPreset> current = get_current_preset();
  278. ERR_FAIL_COND(current.is_null());
  279. Set<String> fset;
  280. List<String> features;
  281. current->get_platform()->get_platform_features(&features);
  282. current->get_platform()->get_preset_features(current, &features);
  283. String custom = current->get_custom_features();
  284. Vector<String> custom_list = custom.split(",");
  285. for (int i = 0; i < custom_list.size(); i++) {
  286. String f = custom_list[i].strip_edges();
  287. if (f != String()) {
  288. features.push_back(f);
  289. }
  290. }
  291. for (List<String>::Element *E = features.front(); E; E = E->next()) {
  292. fset.insert(E->get());
  293. }
  294. custom_feature_display->clear();
  295. for (Set<String>::Element *E = fset.front(); E; E = E->next()) {
  296. String f = E->get();
  297. if (E->next()) {
  298. f += ", ";
  299. }
  300. custom_feature_display->add_text(f);
  301. }
  302. }
  303. void ProjectExportDialog::_custom_features_changed(const String &p_text) {
  304. if (updating) {
  305. return;
  306. }
  307. Ref<EditorExportPreset> current = get_current_preset();
  308. ERR_FAIL_COND(current.is_null());
  309. current->set_custom_features(p_text);
  310. _update_feature_list();
  311. }
  312. void ProjectExportDialog::_tab_changed(int) {
  313. _update_feature_list();
  314. }
  315. void ProjectExportDialog::_update_parameters(const String &p_edited_property) {
  316. _update_current_preset();
  317. }
  318. void ProjectExportDialog::_runnable_pressed() {
  319. if (updating) {
  320. return;
  321. }
  322. Ref<EditorExportPreset> current = get_current_preset();
  323. ERR_FAIL_COND(current.is_null());
  324. if (runnable->is_pressed()) {
  325. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  326. Ref<EditorExportPreset> p = EditorExport::get_singleton()->get_export_preset(i);
  327. if (p->get_platform() == current->get_platform()) {
  328. p->set_runnable(current == p);
  329. }
  330. }
  331. } else {
  332. current->set_runnable(false);
  333. }
  334. _update_presets();
  335. }
  336. void ProjectExportDialog::_name_changed(const String &p_string) {
  337. if (updating) {
  338. return;
  339. }
  340. Ref<EditorExportPreset> current = get_current_preset();
  341. ERR_FAIL_COND(current.is_null());
  342. current->set_name(p_string);
  343. _update_presets();
  344. }
  345. void ProjectExportDialog::set_export_path(const String &p_value) {
  346. Ref<EditorExportPreset> current = get_current_preset();
  347. ERR_FAIL_COND(current.is_null());
  348. current->set_export_path(p_value);
  349. }
  350. String ProjectExportDialog::get_export_path() {
  351. Ref<EditorExportPreset> current = get_current_preset();
  352. ERR_FAIL_COND_V(current.is_null(), String(""));
  353. return current->get_export_path();
  354. }
  355. Ref<EditorExportPreset> ProjectExportDialog::get_current_preset() const {
  356. return EditorExport::get_singleton()->get_export_preset(presets->get_current());
  357. }
  358. void ProjectExportDialog::_export_path_changed(const StringName &p_property, const Variant &p_value, const String &p_field, bool p_changing) {
  359. if (updating) {
  360. return;
  361. }
  362. Ref<EditorExportPreset> current = get_current_preset();
  363. ERR_FAIL_COND(current.is_null());
  364. current->set_export_path(p_value);
  365. _update_presets();
  366. _update_export_all();
  367. }
  368. void ProjectExportDialog::_open_key_help_link() {
  369. OS::get_singleton()->shell_open(vformat("%s/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL));
  370. }
  371. void ProjectExportDialog::_script_export_mode_changed(int p_mode) {
  372. if (updating) {
  373. return;
  374. }
  375. Ref<EditorExportPreset> current = get_current_preset();
  376. ERR_FAIL_COND(current.is_null());
  377. current->set_script_export_mode(p_mode);
  378. _update_current_preset();
  379. }
  380. void ProjectExportDialog::_script_encryption_key_changed(const String &p_key) {
  381. if (updating) {
  382. return;
  383. }
  384. Ref<EditorExportPreset> current = get_current_preset();
  385. ERR_FAIL_COND(current.is_null());
  386. current->set_script_encryption_key(p_key);
  387. updating_script_key = true;
  388. _update_current_preset();
  389. updating_script_key = false;
  390. }
  391. bool ProjectExportDialog::_validate_script_encryption_key(const String &p_key) {
  392. bool is_valid = false;
  393. if (!p_key.empty() && p_key.is_valid_hex_number(false) && p_key.length() == 64) {
  394. is_valid = true;
  395. }
  396. return is_valid;
  397. }
  398. void ProjectExportDialog::_duplicate_preset() {
  399. Ref<EditorExportPreset> current = get_current_preset();
  400. if (current.is_null()) {
  401. return;
  402. }
  403. Ref<EditorExportPreset> preset = current->get_platform()->create_preset();
  404. ERR_FAIL_COND(!preset.is_valid());
  405. String name = current->get_name() + " (copy)";
  406. bool make_runnable = true;
  407. while (true) {
  408. bool valid = true;
  409. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  410. Ref<EditorExportPreset> p = EditorExport::get_singleton()->get_export_preset(i);
  411. if (p->get_platform() == preset->get_platform() && p->is_runnable()) {
  412. make_runnable = false;
  413. }
  414. if (p->get_name() == name) {
  415. valid = false;
  416. break;
  417. }
  418. }
  419. if (valid) {
  420. break;
  421. }
  422. name += " (copy)";
  423. }
  424. preset->set_name(name);
  425. if (make_runnable) {
  426. preset->set_runnable(make_runnable);
  427. }
  428. preset->set_export_filter(current->get_export_filter());
  429. preset->set_include_filter(current->get_include_filter());
  430. preset->set_exclude_filter(current->get_exclude_filter());
  431. preset->set_custom_features(current->get_custom_features());
  432. for (const List<PropertyInfo>::Element *E = current->get_properties().front(); E; E = E->next()) {
  433. preset->set(E->get().name, current->get(E->get().name));
  434. }
  435. EditorExport::get_singleton()->add_export_preset(preset);
  436. _update_presets();
  437. _edit_preset(EditorExport::get_singleton()->get_export_preset_count() - 1);
  438. }
  439. void ProjectExportDialog::_delete_preset() {
  440. Ref<EditorExportPreset> current = get_current_preset();
  441. if (current.is_null()) {
  442. return;
  443. }
  444. delete_confirm->set_text(vformat(TTR("Delete preset '%s'?"), current->get_name()));
  445. delete_confirm->popup_centered_minsize();
  446. }
  447. void ProjectExportDialog::_delete_preset_confirm() {
  448. int idx = presets->get_current();
  449. _edit_preset(-1);
  450. export_button->set_disabled(true);
  451. get_ok()->set_disabled(true);
  452. EditorExport::get_singleton()->remove_export_preset(idx);
  453. _update_presets();
  454. // The Export All button might become enabled (if all other presets have an export path defined),
  455. // or it could be disabled (if there are no presets anymore).
  456. _update_export_all();
  457. }
  458. Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
  459. if (p_from == presets) {
  460. int pos = presets->get_item_at_position(p_point, true);
  461. if (pos >= 0) {
  462. Dictionary d;
  463. d["type"] = "export_preset";
  464. d["preset"] = pos;
  465. HBoxContainer *drag = memnew(HBoxContainer);
  466. TextureRect *tr = memnew(TextureRect);
  467. tr->set_texture(presets->get_item_icon(pos));
  468. drag->add_child(tr);
  469. Label *label = memnew(Label);
  470. label->set_text(presets->get_item_text(pos));
  471. drag->add_child(label);
  472. set_drag_preview(drag);
  473. return d;
  474. }
  475. }
  476. return Variant();
  477. }
  478. bool ProjectExportDialog::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
  479. if (p_from == presets) {
  480. Dictionary d = p_data;
  481. if (!d.has("type") || String(d["type"]) != "export_preset") {
  482. return false;
  483. }
  484. if (presets->get_item_at_position(p_point, true) < 0 && !presets->is_pos_at_end_of_items(p_point)) {
  485. return false;
  486. }
  487. }
  488. return true;
  489. }
  490. void ProjectExportDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
  491. if (p_from == presets) {
  492. Dictionary d = p_data;
  493. int from_pos = d["preset"];
  494. int to_pos = -1;
  495. if (presets->get_item_at_position(p_point, true) >= 0) {
  496. to_pos = presets->get_item_at_position(p_point, true);
  497. }
  498. if (to_pos == -1 && !presets->is_pos_at_end_of_items(p_point)) {
  499. return;
  500. }
  501. if (to_pos == from_pos) {
  502. return;
  503. } else if (to_pos > from_pos) {
  504. to_pos--;
  505. }
  506. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(from_pos);
  507. EditorExport::get_singleton()->remove_export_preset(from_pos);
  508. EditorExport::get_singleton()->add_export_preset(preset, to_pos);
  509. _update_presets();
  510. if (to_pos >= 0) {
  511. _edit_preset(to_pos);
  512. } else {
  513. _edit_preset(presets->get_item_count() - 1);
  514. }
  515. }
  516. }
  517. void ProjectExportDialog::_export_type_changed(int p_which) {
  518. if (updating) {
  519. return;
  520. }
  521. Ref<EditorExportPreset> current = get_current_preset();
  522. if (current.is_null()) {
  523. return;
  524. }
  525. current->set_export_filter(EditorExportPreset::ExportFilter(p_which));
  526. updating = true;
  527. _fill_resource_tree();
  528. updating = false;
  529. }
  530. void ProjectExportDialog::_filter_changed(const String &p_filter) {
  531. if (updating) {
  532. return;
  533. }
  534. Ref<EditorExportPreset> current = get_current_preset();
  535. if (current.is_null()) {
  536. return;
  537. }
  538. current->set_include_filter(include_filters->get_text());
  539. current->set_exclude_filter(exclude_filters->get_text());
  540. }
  541. void ProjectExportDialog::_fill_resource_tree() {
  542. include_files->clear();
  543. include_label->hide();
  544. include_margin->hide();
  545. Ref<EditorExportPreset> current = get_current_preset();
  546. if (current.is_null()) {
  547. return;
  548. }
  549. EditorExportPreset::ExportFilter f = current->get_export_filter();
  550. if (f == EditorExportPreset::EXPORT_ALL_RESOURCES) {
  551. return;
  552. }
  553. include_label->show();
  554. include_margin->show();
  555. TreeItem *root = include_files->create_item();
  556. _fill_tree(EditorFileSystem::get_singleton()->get_filesystem(), root, current, f == EditorExportPreset::EXPORT_SELECTED_SCENES);
  557. }
  558. bool ProjectExportDialog::_fill_tree(EditorFileSystemDirectory *p_dir, TreeItem *p_item, Ref<EditorExportPreset> &current, bool p_only_scenes) {
  559. p_item->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  560. p_item->set_icon(0, get_icon("folder", "FileDialog"));
  561. p_item->set_text(0, p_dir->get_name() + "/");
  562. p_item->set_editable(0, true);
  563. p_item->set_metadata(0, p_dir->get_path());
  564. bool used = false;
  565. bool checked = true;
  566. for (int i = 0; i < p_dir->get_subdir_count(); i++) {
  567. TreeItem *subdir = include_files->create_item(p_item);
  568. if (_fill_tree(p_dir->get_subdir(i), subdir, current, p_only_scenes)) {
  569. used = true;
  570. checked = checked && subdir->is_checked(0);
  571. } else {
  572. memdelete(subdir);
  573. }
  574. }
  575. for (int i = 0; i < p_dir->get_file_count(); i++) {
  576. String type = p_dir->get_file_type(i);
  577. if (p_only_scenes && type != "PackedScene") {
  578. continue;
  579. }
  580. TreeItem *file = include_files->create_item(p_item);
  581. file->set_cell_mode(0, TreeItem::CELL_MODE_CHECK);
  582. file->set_text(0, p_dir->get_file(i));
  583. String path = p_dir->get_file_path(i);
  584. file->set_icon(0, EditorNode::get_singleton()->get_class_icon(type));
  585. file->set_editable(0, true);
  586. file->set_checked(0, current->has_export_file(path));
  587. file->set_metadata(0, path);
  588. checked = checked && file->is_checked(0);
  589. used = true;
  590. }
  591. p_item->set_checked(0, checked);
  592. return used;
  593. }
  594. void ProjectExportDialog::_tree_changed() {
  595. if (updating) {
  596. return;
  597. }
  598. Ref<EditorExportPreset> current = get_current_preset();
  599. if (current.is_null()) {
  600. return;
  601. }
  602. TreeItem *item = include_files->get_edited();
  603. if (!item) {
  604. return;
  605. }
  606. String path = item->get_metadata(0);
  607. bool added = item->is_checked(0);
  608. if (path.ends_with("/")) {
  609. _check_dir_recursive(item, added);
  610. } else {
  611. if (added) {
  612. current->add_export_file(path);
  613. } else {
  614. current->remove_export_file(path);
  615. }
  616. }
  617. _refresh_parent_checks(item); // Makes parent folder checked if all files/folders are checked.
  618. }
  619. void ProjectExportDialog::_check_dir_recursive(TreeItem *p_dir, bool p_checked) {
  620. for (TreeItem *child = p_dir->get_children(); child; child = child->get_next()) {
  621. String path = child->get_metadata(0);
  622. child->set_checked(0, p_checked);
  623. if (path.ends_with("/")) {
  624. _check_dir_recursive(child, p_checked);
  625. } else {
  626. if (p_checked) {
  627. get_current_preset()->add_export_file(path);
  628. } else {
  629. get_current_preset()->remove_export_file(path);
  630. }
  631. }
  632. }
  633. }
  634. void ProjectExportDialog::_refresh_parent_checks(TreeItem *p_item) {
  635. TreeItem *parent = p_item->get_parent();
  636. if (!parent) {
  637. return;
  638. }
  639. bool checked = true;
  640. for (TreeItem *child = parent->get_children(); child; child = child->get_next()) {
  641. checked = checked && child->is_checked(0);
  642. if (!checked) {
  643. break;
  644. }
  645. }
  646. parent->set_checked(0, checked);
  647. _refresh_parent_checks(parent);
  648. }
  649. void ProjectExportDialog::_export_pck_zip() {
  650. Ref<EditorExportPreset> current = get_current_preset();
  651. ERR_FAIL_COND(current.is_null());
  652. String dir = current->get_export_path().get_base_dir();
  653. export_pck_zip->set_current_dir(dir);
  654. export_pck_zip->popup_centered_ratio();
  655. }
  656. void ProjectExportDialog::_export_pck_zip_selected(const String &p_path) {
  657. Ref<EditorExportPreset> current = get_current_preset();
  658. ERR_FAIL_COND(current.is_null());
  659. Ref<EditorExportPlatform> platform = current->get_platform();
  660. ERR_FAIL_COND(platform.is_null());
  661. if (p_path.ends_with(".zip")) {
  662. platform->export_zip(current, export_pck_zip_debug->is_pressed(), p_path);
  663. } else if (p_path.ends_with(".pck")) {
  664. platform->export_pack(current, export_pck_zip_debug->is_pressed(), p_path);
  665. }
  666. }
  667. void ProjectExportDialog::_open_export_template_manager() {
  668. EditorNode::get_singleton()->open_export_template_manager();
  669. hide();
  670. }
  671. void ProjectExportDialog::_validate_export_path(const String &p_path) {
  672. // Disable export via OK button or Enter key if LineEdit has an empty filename
  673. bool invalid_path = (p_path.get_file().get_basename() == "");
  674. // Check if state change before needlessly messing with signals
  675. if (invalid_path && export_project->get_ok()->is_disabled()) {
  676. return;
  677. }
  678. if (!invalid_path && !export_project->get_ok()->is_disabled()) {
  679. return;
  680. }
  681. if (invalid_path) {
  682. export_project->get_ok()->set_disabled(true);
  683. export_project->get_line_edit()->disconnect("text_entered", export_project, "_file_entered");
  684. } else {
  685. export_project->get_ok()->set_disabled(false);
  686. export_project->get_line_edit()->connect("text_entered", export_project, "_file_entered");
  687. }
  688. }
  689. void ProjectExportDialog::_export_project() {
  690. Ref<EditorExportPreset> current = get_current_preset();
  691. ERR_FAIL_COND(current.is_null());
  692. Ref<EditorExportPlatform> platform = current->get_platform();
  693. ERR_FAIL_COND(platform.is_null());
  694. export_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  695. export_project->clear_filters();
  696. List<String> extension_list = platform->get_binary_extensions(current);
  697. for (int i = 0; i < extension_list.size(); i++) {
  698. export_project->add_filter("*." + extension_list[i] + " ; " + platform->get_name() + " Export");
  699. }
  700. if (current->get_export_path() != "") {
  701. export_project->set_current_path(current->get_export_path());
  702. } else {
  703. if (extension_list.size() >= 1) {
  704. export_project->set_current_file(default_filename + "." + extension_list[0]);
  705. } else {
  706. export_project->set_current_file(default_filename);
  707. }
  708. }
  709. // Ensure that signal is connected if previous attempt left it disconnected with _validate_export_path
  710. if (!export_project->get_line_edit()->is_connected("text_entered", export_project, "_file_entered")) {
  711. export_project->get_ok()->set_disabled(false);
  712. export_project->get_line_edit()->connect("text_entered", export_project, "_file_entered");
  713. }
  714. export_project->set_mode(EditorFileDialog::MODE_SAVE_FILE);
  715. export_project->popup_centered_ratio();
  716. }
  717. void ProjectExportDialog::_export_project_to_path(const String &p_path) {
  718. // Save this name for use in future exports (but drop the file extension)
  719. default_filename = p_path.get_file().get_basename();
  720. EditorSettings::get_singleton()->set_project_metadata("export_options", "default_filename", default_filename);
  721. Ref<EditorExportPreset> current = get_current_preset();
  722. ERR_FAIL_COND(current.is_null());
  723. Ref<EditorExportPlatform> platform = current->get_platform();
  724. ERR_FAIL_COND(platform.is_null());
  725. current->set_export_path(p_path);
  726. platform->clear_messages();
  727. Error err = platform->export_project(current, export_debug->is_pressed(), p_path, 0);
  728. result_dialog_log->clear();
  729. if (err != ERR_SKIP) {
  730. if (platform->fill_log_messages(result_dialog_log, err)) {
  731. result_dialog->popup_centered_ratio(0.5);
  732. }
  733. }
  734. }
  735. void ProjectExportDialog::_export_all_dialog() {
  736. export_all_dialog->show();
  737. export_all_dialog->popup_centered_minsize(Size2(300, 80));
  738. }
  739. void ProjectExportDialog::_export_all_dialog_action(const String &p_str) {
  740. export_all_dialog->hide();
  741. _export_all(p_str != "release");
  742. }
  743. void ProjectExportDialog::_export_all(bool p_debug) {
  744. String mode = p_debug ? TTR("Debug") : TTR("Release");
  745. EditorProgress ep("exportall", TTR("Exporting All") + " " + mode, EditorExport::get_singleton()->get_export_preset_count(), true);
  746. bool show_dialog = false;
  747. result_dialog_log->clear();
  748. for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
  749. Ref<EditorExportPreset> preset = EditorExport::get_singleton()->get_export_preset(i);
  750. ERR_FAIL_COND(preset.is_null());
  751. Ref<EditorExportPlatform> platform = preset->get_platform();
  752. ERR_FAIL_COND(platform.is_null());
  753. ep.step(preset->get_name(), i);
  754. platform->clear_messages();
  755. Error err = platform->export_project(preset, p_debug, preset->get_export_path(), 0);
  756. if (err == ERR_SKIP) {
  757. return;
  758. }
  759. bool has_messages = platform->fill_log_messages(result_dialog_log, err);
  760. show_dialog = show_dialog || has_messages;
  761. }
  762. if (show_dialog) {
  763. result_dialog->popup_centered_ratio(0.5);
  764. }
  765. }
  766. void ProjectExportDialog::_bind_methods() {
  767. ClassDB::bind_method("_add_preset", &ProjectExportDialog::_add_preset);
  768. ClassDB::bind_method("_edit_preset", &ProjectExportDialog::_edit_preset);
  769. ClassDB::bind_method("_update_parameters", &ProjectExportDialog::_update_parameters);
  770. ClassDB::bind_method("_runnable_pressed", &ProjectExportDialog::_runnable_pressed);
  771. ClassDB::bind_method("_name_changed", &ProjectExportDialog::_name_changed);
  772. ClassDB::bind_method("_duplicate_preset", &ProjectExportDialog::_duplicate_preset);
  773. ClassDB::bind_method("_delete_preset", &ProjectExportDialog::_delete_preset);
  774. ClassDB::bind_method("_delete_preset_confirm", &ProjectExportDialog::_delete_preset_confirm);
  775. ClassDB::bind_method("get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
  776. ClassDB::bind_method("can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw);
  777. ClassDB::bind_method("drop_data_fw", &ProjectExportDialog::drop_data_fw);
  778. ClassDB::bind_method("_export_type_changed", &ProjectExportDialog::_export_type_changed);
  779. ClassDB::bind_method("_filter_changed", &ProjectExportDialog::_filter_changed);
  780. ClassDB::bind_method("_tree_changed", &ProjectExportDialog::_tree_changed);
  781. ClassDB::bind_method("_export_pck_zip", &ProjectExportDialog::_export_pck_zip);
  782. ClassDB::bind_method("_export_pck_zip_selected", &ProjectExportDialog::_export_pck_zip_selected);
  783. ClassDB::bind_method("_open_export_template_manager", &ProjectExportDialog::_open_export_template_manager);
  784. ClassDB::bind_method("_validate_export_path", &ProjectExportDialog::_validate_export_path);
  785. ClassDB::bind_method("_export_path_changed", &ProjectExportDialog::_export_path_changed);
  786. ClassDB::bind_method("_open_key_help_link", &ProjectExportDialog::_open_key_help_link);
  787. ClassDB::bind_method("_script_export_mode_changed", &ProjectExportDialog::_script_export_mode_changed);
  788. ClassDB::bind_method("_script_encryption_key_changed", &ProjectExportDialog::_script_encryption_key_changed);
  789. ClassDB::bind_method("_export_project", &ProjectExportDialog::_export_project);
  790. ClassDB::bind_method("_export_project_to_path", &ProjectExportDialog::_export_project_to_path);
  791. ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all);
  792. ClassDB::bind_method("_export_all_dialog", &ProjectExportDialog::_export_all_dialog);
  793. ClassDB::bind_method("_export_all_dialog_action", &ProjectExportDialog::_export_all_dialog_action);
  794. ClassDB::bind_method("_custom_features_changed", &ProjectExportDialog::_custom_features_changed);
  795. ClassDB::bind_method("_tab_changed", &ProjectExportDialog::_tab_changed);
  796. ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path);
  797. ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path);
  798. ClassDB::bind_method("get_current_preset", &ProjectExportDialog::get_current_preset);
  799. ClassDB::bind_method("_force_update_current_preset_parameters", &ProjectExportDialog::_force_update_current_preset_parameters);
  800. ADD_PROPERTY(PropertyInfo(Variant::STRING, "export_path"), "set_export_path", "get_export_path");
  801. }
  802. ProjectExportDialog::ProjectExportDialog() {
  803. set_title(TTR("Export"));
  804. set_resizable(true);
  805. VBoxContainer *main_vb = memnew(VBoxContainer);
  806. add_child(main_vb);
  807. HSplitContainer *hbox = memnew(HSplitContainer);
  808. main_vb->add_child(hbox);
  809. hbox->set_v_size_flags(SIZE_EXPAND_FILL);
  810. // Presets list.
  811. VBoxContainer *preset_vb = memnew(VBoxContainer);
  812. preset_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  813. hbox->add_child(preset_vb);
  814. HBoxContainer *preset_hb = memnew(HBoxContainer);
  815. preset_hb->add_child(memnew(Label(TTR("Presets"))));
  816. preset_hb->add_spacer();
  817. preset_vb->add_child(preset_hb);
  818. add_preset = memnew(MenuButton);
  819. add_preset->set_text(TTR("Add..."));
  820. add_preset->get_popup()->connect("index_pressed", this, "_add_preset");
  821. preset_hb->add_child(add_preset);
  822. MarginContainer *mc = memnew(MarginContainer);
  823. preset_vb->add_child(mc);
  824. mc->set_v_size_flags(SIZE_EXPAND_FILL);
  825. presets = memnew(ItemList);
  826. presets->set_drag_forwarding(this);
  827. mc->add_child(presets);
  828. presets->connect("item_selected", this, "_edit_preset");
  829. duplicate_preset = memnew(ToolButton);
  830. duplicate_preset->set_tooltip(TTR("Duplicate"));
  831. preset_hb->add_child(duplicate_preset);
  832. duplicate_preset->connect("pressed", this, "_duplicate_preset");
  833. delete_preset = memnew(ToolButton);
  834. delete_preset->set_tooltip(TTR("Delete"));
  835. preset_hb->add_child(delete_preset);
  836. delete_preset->connect("pressed", this, "_delete_preset");
  837. // Preset settings.
  838. VBoxContainer *settings_vb = memnew(VBoxContainer);
  839. settings_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  840. hbox->add_child(settings_vb);
  841. name = memnew(LineEdit);
  842. settings_vb->add_margin_child(TTR("Name:"), name);
  843. name->connect("text_changed", this, "_name_changed");
  844. runnable = memnew(CheckButton);
  845. runnable->set_text(TTR("Runnable"));
  846. runnable->set_tooltip(TTR("If checked, the preset will be available for use in one-click deploy.\nOnly one preset per platform may be marked as runnable."));
  847. runnable->connect("pressed", this, "_runnable_pressed");
  848. settings_vb->add_child(runnable);
  849. export_path = memnew(EditorPropertyPath);
  850. settings_vb->add_child(export_path);
  851. export_path->set_label(TTR("Export Path"));
  852. export_path->set_object_and_property(this, "export_path");
  853. export_path->set_save_mode();
  854. export_path->connect("property_changed", this, "_export_path_changed");
  855. // Subsections.
  856. sections = memnew(TabContainer);
  857. sections->set_tab_align(TabContainer::ALIGN_LEFT);
  858. sections->set_use_hidden_tabs_for_min_size(true);
  859. settings_vb->add_child(sections);
  860. sections->set_v_size_flags(SIZE_EXPAND_FILL);
  861. // Main preset parameters.
  862. parameters = memnew(EditorInspector);
  863. sections->add_child(parameters);
  864. parameters->set_name(TTR("Options"));
  865. parameters->set_v_size_flags(SIZE_EXPAND_FILL);
  866. parameters->set_property_name_style(EditorPropertyNameProcessor::get_settings_style());
  867. parameters->connect("property_edited", this, "_update_parameters");
  868. EditorExport::get_singleton()->connect("export_presets_updated", this, "_force_update_current_preset_parameters");
  869. // Resources export parameters.
  870. VBoxContainer *resources_vb = memnew(VBoxContainer);
  871. sections->add_child(resources_vb);
  872. resources_vb->set_name(TTR("Resources"));
  873. export_filter = memnew(OptionButton);
  874. export_filter->add_item(TTR("Export all resources in the project"));
  875. export_filter->add_item(TTR("Export selected scenes (and dependencies)"));
  876. export_filter->add_item(TTR("Export selected resources (and dependencies)"));
  877. resources_vb->add_margin_child(TTR("Export Mode:"), export_filter);
  878. export_filter->connect("item_selected", this, "_export_type_changed");
  879. include_label = memnew(Label);
  880. include_label->set_text(TTR("Resources to export:"));
  881. resources_vb->add_child(include_label);
  882. include_margin = memnew(MarginContainer);
  883. include_margin->set_v_size_flags(SIZE_EXPAND_FILL);
  884. resources_vb->add_child(include_margin);
  885. include_files = memnew(Tree);
  886. include_margin->add_child(include_files);
  887. include_files->connect("item_edited", this, "_tree_changed");
  888. include_filters = memnew(LineEdit);
  889. resources_vb->add_margin_child(
  890. TTR("Filters to export non-resource files/folders\n(comma-separated, e.g: *.json, *.txt, docs/*)"),
  891. include_filters);
  892. include_filters->connect("text_changed", this, "_filter_changed");
  893. exclude_filters = memnew(LineEdit);
  894. resources_vb->add_margin_child(
  895. TTR("Filters to exclude files/folders from project\n(comma-separated, e.g: *.json, *.txt, docs/*)"),
  896. exclude_filters);
  897. exclude_filters->connect("text_changed", this, "_filter_changed");
  898. // Feature tags.
  899. VBoxContainer *feature_vb = memnew(VBoxContainer);
  900. feature_vb->set_name(TTR("Features"));
  901. custom_features = memnew(LineEdit);
  902. custom_features->connect("text_changed", this, "_custom_features_changed");
  903. feature_vb->add_margin_child(TTR("Custom (comma-separated):"), custom_features);
  904. custom_feature_display = memnew(RichTextLabel);
  905. custom_feature_display->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  906. feature_vb->add_margin_child(TTR("Feature List:"), custom_feature_display, true);
  907. sections->add_child(feature_vb);
  908. // Script export parameters.
  909. updating_script_key = false;
  910. VBoxContainer *script_vb = memnew(VBoxContainer);
  911. script_vb->set_name(TTR("Script"));
  912. script_mode = memnew(OptionButton);
  913. script_vb->add_margin_child(TTR("GDScript Export Mode:"), script_mode);
  914. script_mode->add_item(TTR("Text"), (int)EditorExportPreset::MODE_SCRIPT_TEXT);
  915. script_mode->add_item(TTR("Compiled Bytecode (Faster Loading)"), (int)EditorExportPreset::MODE_SCRIPT_COMPILED);
  916. script_mode->add_item(TTR("Encrypted (Provide Key Below)"), (int)EditorExportPreset::MODE_SCRIPT_ENCRYPTED);
  917. script_mode->connect("item_selected", this, "_script_export_mode_changed");
  918. script_key = memnew(LineEdit);
  919. script_key->connect("text_changed", this, "_script_encryption_key_changed");
  920. script_key_error = memnew(Label);
  921. script_key_error->set_text(String::utf8("• ") + TTR("Invalid Encryption Key (must be 64 hexadecimal characters long)"));
  922. script_key_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
  923. script_vb->add_margin_child(TTR("GDScript Encryption Key (256-bits as hexadecimal):"), script_key);
  924. script_vb->add_child(script_key_error);
  925. sections->add_child(script_vb);
  926. Label *sec_info = memnew(Label);
  927. sec_info->set_text(TTR("Note: Encryption key needs to be stored in the binary,\nyou need to build the export templates from source."));
  928. script_vb->add_child(sec_info);
  929. LinkButton *sec_more_info = memnew(LinkButton);
  930. sec_more_info->set_text(TTR("More Info..."));
  931. sec_more_info->connect("pressed", this, "_open_key_help_link");
  932. script_vb->add_child(sec_more_info);
  933. sections->connect("tab_changed", this, "_tab_changed");
  934. // Disable by default.
  935. name->set_editable(false);
  936. export_path->hide();
  937. runnable->set_disabled(true);
  938. duplicate_preset->set_disabled(true);
  939. delete_preset->set_disabled(true);
  940. script_key_error->hide();
  941. sections->hide();
  942. parameters->edit(nullptr);
  943. // Deletion dialog.
  944. delete_confirm = memnew(ConfirmationDialog);
  945. add_child(delete_confirm);
  946. delete_confirm->get_ok()->set_text(TTR("Delete"));
  947. delete_confirm->connect("confirmed", this, "_delete_preset_confirm");
  948. // Export buttons, dialogs and errors.
  949. updating = false;
  950. get_cancel()->set_text(TTR("Close"));
  951. get_ok()->set_text(TTR("Export PCK/Zip..."));
  952. export_button = add_button(TTR("Export Project..."), !OS::get_singleton()->get_swap_ok_cancel(), "export");
  953. export_button->connect("pressed", this, "_export_project");
  954. // Disable initially before we select a valid preset
  955. export_button->set_disabled(true);
  956. get_ok()->set_disabled(true);
  957. export_all_dialog = memnew(ConfirmationDialog);
  958. add_child(export_all_dialog);
  959. export_all_dialog->set_title(TTR("Export All"));
  960. export_all_dialog->set_text(TTR("Choose an export mode:"));
  961. export_all_dialog->get_ok()->hide();
  962. export_all_dialog->add_button(TTR("Debug"), true, "debug");
  963. export_all_dialog->add_button(TTR("Release"), true, "release");
  964. export_all_dialog->connect("custom_action", this, "_export_all_dialog_action");
  965. export_all_button = add_button(TTR("Export All..."), !OS::get_singleton()->get_swap_ok_cancel(), "export");
  966. export_all_button->connect("pressed", this, "_export_all_dialog");
  967. export_all_button->set_disabled(true);
  968. export_pck_zip = memnew(EditorFileDialog);
  969. export_pck_zip->add_filter("*.zip ; " + TTR("ZIP File"));
  970. export_pck_zip->add_filter("*.pck ; " + TTR("Godot Project Pack"));
  971. export_pck_zip->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  972. export_pck_zip->set_mode(EditorFileDialog::MODE_SAVE_FILE);
  973. add_child(export_pck_zip);
  974. export_pck_zip->connect("file_selected", this, "_export_pck_zip_selected");
  975. export_error = memnew(Label);
  976. main_vb->add_child(export_error);
  977. export_error->hide();
  978. export_error->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
  979. export_warning = memnew(Label);
  980. main_vb->add_child(export_warning);
  981. export_warning->hide();
  982. export_warning->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("warning_color", "Editor"));
  983. export_templates_error = memnew(HBoxContainer);
  984. main_vb->add_child(export_templates_error);
  985. export_templates_error->hide();
  986. Label *export_error2 = memnew(Label);
  987. export_templates_error->add_child(export_error2);
  988. export_error2->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor"));
  989. export_error2->set_text(" - " + TTR("Export templates for this platform are missing:") + " ");
  990. result_dialog = memnew(AcceptDialog);
  991. result_dialog->set_title(TTR("Project Export"));
  992. result_dialog_log = memnew(RichTextLabel);
  993. result_dialog_log->set_custom_minimum_size(Size2(300, 80) * EDSCALE);
  994. result_dialog->add_child(result_dialog_log);
  995. main_vb->add_child(result_dialog);
  996. result_dialog->hide();
  997. LinkButton *download_templates = memnew(LinkButton);
  998. download_templates->set_text(TTR("Manage Export Templates"));
  999. download_templates->set_v_size_flags(SIZE_SHRINK_CENTER);
  1000. export_templates_error->add_child(download_templates);
  1001. download_templates->connect("pressed", this, "_open_export_template_manager");
  1002. export_project = memnew(EditorFileDialog);
  1003. export_project->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
  1004. add_child(export_project);
  1005. export_project->connect("file_selected", this, "_export_project_to_path");
  1006. export_project->get_line_edit()->connect("text_changed", this, "_validate_export_path");
  1007. export_debug = memnew(CheckBox);
  1008. export_debug->set_text(TTR("Export With Debug"));
  1009. export_debug->set_pressed(true);
  1010. export_debug->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
  1011. export_project->get_vbox()->add_child(export_debug);
  1012. export_pck_zip_debug = memnew(CheckBox);
  1013. export_pck_zip_debug->set_text(TTR("Export With Debug"));
  1014. export_pck_zip_debug->set_pressed(true);
  1015. export_pck_zip_debug->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
  1016. export_pck_zip->get_vbox()->add_child(export_pck_zip_debug);
  1017. set_hide_on_ok(false);
  1018. editor_icons = "EditorIcons";
  1019. default_filename = EditorSettings::get_singleton()->get_project_metadata("export_options", "default_filename", "");
  1020. // If no default set, use project name
  1021. if (default_filename == "") {
  1022. // If no project name defined, use a sane default
  1023. default_filename = ProjectSettings::get_singleton()->get("application/config/name");
  1024. if (default_filename == "") {
  1025. default_filename = "UnnamedProject";
  1026. }
  1027. }
  1028. }
  1029. ProjectExportDialog::~ProjectExportDialog() {
  1030. }