project_export.cpp 41 KB

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