summaryrefslogtreecommitdiff
path: root/editor/project_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'editor/project_manager.cpp')
-rw-r--r--editor/project_manager.cpp334
1 files changed, 270 insertions, 64 deletions
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index bd700342f6..3a6a73d3cc 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -72,16 +72,26 @@ private:
MESSAGE_SUCCESS
};
+ enum InputType {
+ PROJECT_PATH,
+ INSTALL_PATH
+ };
+
Mode mode;
Button *browse;
+ Button *install_browse;
Button *create_dir;
Container *name_container;
Container *path_container;
+ Container *install_path_container;
Label *msg;
LineEdit *project_path;
LineEdit *project_name;
+ LineEdit *install_path;
TextureRect *status_rect;
+ TextureRect *install_status_rect;
FileDialog *fdialog;
+ FileDialog *fdialog_install;
String zip_path;
String zip_title;
AcceptDialog *dialog_error;
@@ -89,10 +99,11 @@ private:
String created_folder_path;
- void set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS) {
+ void set_message(const String &p_msg, MessageType p_type = MESSAGE_SUCCESS, InputType input_type = PROJECT_PATH) {
msg->set_text(p_msg);
- Ref<Texture> current_icon = status_rect->get_texture();
+ Ref<Texture> current_path_icon = status_rect->get_texture();
+ Ref<Texture> current_install_icon = install_status_rect->get_texture();
Ref<Texture> new_icon;
switch (p_type) {
@@ -119,8 +130,11 @@ private:
} break;
}
- if (current_icon != new_icon)
+ if (current_path_icon != new_icon && input_type == PROJECT_PATH) {
status_rect->set_texture(new_icon);
+ } else if (current_install_icon != new_icon && input_type == INSTALL_PATH) {
+ install_status_rect->set_texture(new_icon);
+ }
set_size(Size2(500, 0) * EDSCALE);
}
@@ -128,11 +142,19 @@ private:
String _test_path() {
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
- String valid_path;
+ String valid_path, valid_install_path;
if (d->change_dir(project_path->get_text()) == OK) {
valid_path = project_path->get_text();
} else if (d->change_dir(project_path->get_text().strip_edges()) == OK) {
valid_path = project_path->get_text().strip_edges();
+ } else if (project_path->get_text().ends_with(".zip")) {
+ if (d->file_exists(project_path->get_text())) {
+ valid_path = project_path->get_text();
+ }
+ } else if (project_path->get_text().strip_edges().ends_with(".zip")) {
+ if (d->file_exists(project_path->get_text().strip_edges())) {
+ valid_path = project_path->get_text().strip_edges();
+ }
}
if (valid_path == "") {
@@ -142,11 +164,94 @@ private:
return "";
}
+ if (mode == MODE_IMPORT && valid_path.ends_with(".zip")) {
+ if (d->change_dir(install_path->get_text()) == OK) {
+ valid_install_path = install_path->get_text();
+ } else if (d->change_dir(install_path->get_text().strip_edges()) == OK) {
+ valid_install_path = install_path->get_text().strip_edges();
+ }
+
+ if (valid_install_path == "") {
+ set_message(TTR("The path does not exist."), MESSAGE_ERROR, INSTALL_PATH);
+ memdelete(d);
+ get_ok()->set_disabled(true);
+ return "";
+ }
+ }
+
if (mode == MODE_IMPORT || mode == MODE_RENAME) {
if (valid_path != "" && !d->file_exists("project.godot")) {
- set_message(TTR("Please choose a 'project.godot' file."), MESSAGE_ERROR);
+ if (valid_path.ends_with(".zip")) {
+ FileAccess *src_f = NULL;
+ zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
+
+ unzFile pkg = unzOpen2(valid_path.utf8().get_data(), &io);
+ if (!pkg) {
+
+ set_message(TTR("Error opening package file, not in zip format."), MESSAGE_ERROR);
+ memdelete(d);
+ get_ok()->set_disabled(true);
+ unzClose(pkg);
+ return "";
+ }
+
+ int ret = unzGoToFirstFile(pkg);
+ while (ret == UNZ_OK) {
+ unz_file_info info;
+ char fname[16384];
+ ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, NULL, 0, NULL, 0);
+
+ if (String(fname).ends_with("project.godot")) {
+ break;
+ }
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+ if (ret == UNZ_END_OF_LIST_OF_FILE) {
+ set_message(TTR("Invalid '.zip' project file, does not contain a 'project.godot' file."), MESSAGE_ERROR);
+ memdelete(d);
+ get_ok()->set_disabled(true);
+ unzClose(pkg);
+ return "";
+ }
+
+ unzClose(pkg);
+
+ // check if the specified install folder is empty, even though this is not an error, it is good to check here
+ d->list_dir_begin();
+ bool is_empty = true;
+ String n = d->get_next();
+ while (n != String()) {
+ if (n != "." && n != "..") {
+ is_empty = false;
+ break;
+ }
+ n = d->get_next();
+ }
+ d->list_dir_end();
+
+ if (!is_empty) {
+
+ set_message(TTR("Please choose an empty folder."), MESSAGE_WARNING, INSTALL_PATH);
+ memdelete(d);
+ get_ok()->set_disabled(true);
+ return "";
+ }
+
+ } else {
+ set_message(TTR("Please choose a 'project.godot' or '.zip' file."), MESSAGE_ERROR);
+ memdelete(d);
+ install_path_container->hide();
+ get_ok()->set_disabled(true);
+ return "";
+ }
+
+ } else if (valid_path.ends_with("zip")) {
+
+ set_message(TTR("Directory already contains a Godot project."), MESSAGE_ERROR, INSTALL_PATH);
memdelete(d);
get_ok()->set_disabled(true);
return "";
@@ -159,7 +264,7 @@ private:
bool is_empty = true;
String n = d->get_next();
while (n != String()) {
- if (!n.begins_with(".")) { // i don't know if this is enough to guarantee an empty dir
+ if (n != "." && n != "..") { // i don't know if this is enough to guarantee an empty dir
is_empty = false;
break;
}
@@ -177,6 +282,7 @@ private:
}
set_message("");
+ set_message("", MESSAGE_SUCCESS, INSTALL_PATH);
memdelete(d);
get_ok()->set_disabled(false);
return valid_path;
@@ -199,6 +305,7 @@ private:
sp = TTR("Imported Project");
project_name->set_text(sp);
+ _text_changed(sp);
}
}
@@ -213,16 +320,26 @@ private:
if (mode == MODE_IMPORT) {
if (p.ends_with("project.godot")) {
p = p.get_base_dir();
+ install_path_container->hide();
+ get_ok()->set_disabled(false);
+ } else if (p.ends_with(".zip")) {
+ install_path->set_text(p.get_base_dir());
+ install_path_container->show();
get_ok()->set_disabled(false);
} else {
- set_message(TTR("Please choose a 'project.godot' file."), MESSAGE_ERROR);
+ set_message(TTR("Please choose a 'project.godot' or '.zip' file."), MESSAGE_ERROR);
get_ok()->set_disabled(true);
return;
}
}
String sp = p.simplify_path();
project_path->set_text(sp);
- get_ok()->call_deferred("grab_focus");
+ _path_text_changed(sp);
+ if (p.ends_with(".zip")) {
+ install_path->call_deferred("grab_focus");
+ } else {
+ get_ok()->call_deferred("grab_focus");
+ }
}
void _path_selected(const String &p_path) {
@@ -230,6 +347,15 @@ private:
String p = p_path;
String sp = p.simplify_path();
project_path->set_text(sp);
+ _path_text_changed(sp);
+ get_ok()->call_deferred("grab_focus");
+ }
+
+ void _install_path_selected(const String &p_path) {
+ String p = p_path;
+ String sp = p.simplify_path();
+ install_path->set_text(sp);
+ _path_text_changed(sp);
get_ok()->call_deferred("grab_focus");
}
@@ -242,16 +368,25 @@ private:
fdialog->set_mode(FileDialog::MODE_OPEN_FILE);
fdialog->clear_filters();
fdialog->add_filter("project.godot ; " VERSION_NAME " Project");
+ fdialog->add_filter("*.zip ; Zip File");
} else {
fdialog->set_mode(FileDialog::MODE_OPEN_DIR);
}
fdialog->popup_centered_ratio();
}
+ void _browse_install_path() {
+ fdialog_install->set_current_dir(install_path->get_text());
+ fdialog_install->set_mode(FileDialog::MODE_OPEN_DIR);
+ fdialog_install->popup_centered_ratio();
+ }
+
void _create_folder() {
- if (project_name->get_text() == "" || created_folder_path != "")
+ if (project_name->get_text() == "" || created_folder_path != "" || project_name->get_text().ends_with(".") || project_name->get_text().ends_with(" ")) {
+ set_message(TTR("Invalid Project Name."), MESSAGE_WARNING);
return;
+ }
DirAccess *d = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
if (d->change_dir(project_path->get_text()) == OK) {
@@ -261,7 +396,9 @@ private:
if (d->make_dir(project_name->get_text()) == OK) {
d->change_dir(project_name->get_text());
- project_path->set_text(d->get_current_dir());
+ String dir_str = d->get_current_dir();
+ project_path->set_text(dir_str);
+ _path_text_changed(dir_str);
created_folder_path = d->get_current_dir();
create_dir->set_disabled(true);
} else {
@@ -321,7 +458,15 @@ private:
} else {
if (mode == MODE_IMPORT) {
- // nothing to do
+
+ if (project_path->get_text().ends_with(".zip")) {
+
+ mode = MODE_INSTALL;
+ ok_pressed();
+
+ return;
+ }
+
} else {
if (mode == MODE_NEW) {
@@ -350,6 +495,11 @@ private:
} else if (mode == MODE_INSTALL) {
+ if (project_path->get_text().ends_with(".zip")) {
+ dir = install_path->get_text();
+ zip_path = project_path->get_text();
+ }
+
FileAccess *src_f = NULL;
zlib_filefunc_def io = zipio_create_io_from_file(&src_f);
@@ -437,7 +587,7 @@ private:
dialog_error->set_text(msg);
dialog_error->popup_centered_minsize();
- } else {
+ } else if (!project_path->get_text().ends_with(".zip")) {
dialog_error->set_text(TTR("Package Installed Successfully!"));
dialog_error->popup_centered_minsize();
}
@@ -473,10 +623,15 @@ private:
_remove_created_folder();
project_path->clear();
+ _path_text_changed("");
project_name->clear();
+ _text_changed("");
if (status_rect->get_texture() == get_icon("StatusError", "EditorIcons"))
msg->show();
+
+ if (install_status_rect->get_texture() == get_icon("StatusError", "EditorIcons"))
+ msg->show();
}
void _notification(int p_what) {
@@ -494,6 +649,8 @@ protected:
ClassDB::bind_method("_path_text_changed", &ProjectDialog::_path_text_changed);
ClassDB::bind_method("_path_selected", &ProjectDialog::_path_selected);
ClassDB::bind_method("_file_selected", &ProjectDialog::_file_selected);
+ ClassDB::bind_method("_install_path_selected", &ProjectDialog::_install_path_selected);
+ ClassDB::bind_method("_browse_install_path", &ProjectDialog::_browse_install_path);
ADD_SIGNAL(MethodInfo("project_created"));
ADD_SIGNAL(MethodInfo("project_renamed"));
}
@@ -521,12 +678,15 @@ public:
project_path->set_editable(false);
browse->hide();
+ install_browse->hide();
set_title(TTR("Rename Project"));
get_ok()->set_text(TTR("Rename"));
name_container->show();
status_rect->hide();
msg->hide();
+ install_path_container->hide();
+ install_status_rect->hide();
get_ok()->set_disabled(false);
ProjectSettings *current = memnew(ProjectSettings);
@@ -538,7 +698,9 @@ public:
msg->show();
get_ok()->set_disabled(true);
} else if (current->has_setting("application/config/name")) {
- project_name->set_text(current->get("application/config/name"));
+ String proj = current->get("application/config/name");
+ project_name->set_text(proj);
+ _text_changed(proj);
}
project_name->call_deferred("grab_focus");
@@ -557,19 +719,25 @@ public:
fdialog->set_current_dir(d->get_current_dir());
memdelete(d);
}
- project_name->set_text(TTR("New Game Project"));
+ String proj = TTR("New Game Project");
+ project_name->set_text(proj);
+ _text_changed(proj);
project_path->set_editable(true);
browse->set_disabled(false);
browse->show();
+ install_browse->set_disabled(false);
+ install_browse->show();
create_dir->show();
status_rect->show();
+ install_status_rect->show();
msg->show();
if (mode == MODE_IMPORT) {
set_title(TTR("Import Existing Project"));
get_ok()->set_text(TTR("Import & Edit"));
name_container->hide();
+ install_path_container->hide();
project_path->grab_focus();
} else if (mode == MODE_NEW) {
@@ -577,6 +745,7 @@ public:
set_title(TTR("Create New Project"));
get_ok()->set_text(TTR("Create & Edit"));
name_container->show();
+ install_path_container->hide();
project_name->grab_focus();
} else if (mode == MODE_INSTALL) {
@@ -584,6 +753,7 @@ public:
set_title(TTR("Install Project:") + " " + zip_title);
get_ok()->set_text(TTR("Install & Edit"));
name_container->hide();
+ install_path_container->hide();
project_path->grab_focus();
}
@@ -631,6 +801,20 @@ public:
project_path->set_h_size_flags(SIZE_EXPAND_FILL);
pphb->add_child(project_path);
+ install_path_container = memnew(VBoxContainer);
+ vb->add_child(install_path_container);
+
+ l = memnew(Label);
+ l->set_text(TTR("Project Installation Path:"));
+ install_path_container->add_child(l);
+
+ HBoxContainer *iphb = memnew(HBoxContainer);
+ install_path_container->add_child(iphb);
+
+ install_path = memnew(LineEdit);
+ install_path->set_h_size_flags(SIZE_EXPAND_FILL);
+ iphb->add_child(install_path);
+
// status icon
status_rect = memnew(TextureRect);
status_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
@@ -641,17 +825,33 @@ public:
browse->connect("pressed", this, "_browse_path");
pphb->add_child(browse);
+ // install status icon
+ install_status_rect = memnew(TextureRect);
+ install_status_rect->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
+ iphb->add_child(install_status_rect);
+
+ install_browse = memnew(Button);
+ install_browse->set_text(TTR("Browse"));
+ install_browse->connect("pressed", this, "_browse_install_path");
+ iphb->add_child(install_browse);
+
msg = memnew(Label);
msg->set_align(Label::ALIGN_CENTER);
vb->add_child(msg);
fdialog = memnew(FileDialog);
fdialog->set_access(FileDialog::ACCESS_FILESYSTEM);
+ fdialog_install = memnew(FileDialog);
+ fdialog_install->set_access(FileDialog::ACCESS_FILESYSTEM);
add_child(fdialog);
+ add_child(fdialog_install);
project_name->connect("text_changed", this, "_text_changed");
project_path->connect("text_changed", this, "_path_text_changed");
+ install_path->connect("text_changed", this, "_path_text_changed");
fdialog->connect("dir_selected", this, "_path_selected");
fdialog->connect("file_selected", this, "_file_selected");
+ fdialog_install->connect("dir_selected", this, "_install_path_selected");
+ fdialog_install->connect("file_selected", this, "_install_path_selected");
set_hide_on_ok(false);
mode = MODE_NEW;
@@ -689,7 +889,7 @@ void ProjectManager::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- if (scroll_children->get_child_count() == 0)
+ if (scroll_children->get_child_count() == 0 && StreamPeerSSL::is_available())
open_templates->popup_centered_minsize();
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -715,17 +915,13 @@ void ProjectManager::_update_project_buttons() {
CanvasItem *item = Object::cast_to<CanvasItem>(scroll_children->get_child(i));
item->update();
-
- Button *show = Object::cast_to<Button>(item->get_node(NodePath("project/path_box/show")));
- if (show) {
- String current = item->get_meta("name");
- show->set_visible(selected_list.has(current));
- }
}
- erase_btn->set_disabled(selected_list.size() < 1);
- open_btn->set_disabled(selected_list.size() < 1);
- rename_btn->set_disabled(selected_list.size() < 1);
+ bool empty_selection = selected_list.empty();
+ erase_btn->set_disabled(empty_selection);
+ open_btn->set_disabled(empty_selection);
+ rename_btn->set_disabled(empty_selection);
+ run_btn->set_disabled(empty_selection);
}
void ProjectManager::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
@@ -1114,7 +1310,6 @@ void ProjectManager::_load_recent_projects() {
path_hb->add_child(show);
show->connect("pressed", this, "_show_project", varray(path));
show->set_tooltip(TTR("Show In File Manager"));
- show->set_visible(false);
Label *fpath = memnew(Label(path));
fpath->set_name("path");
@@ -1195,7 +1390,7 @@ void ProjectManager::_open_project_confirm() {
return;
}
- print_line("OPENING: " + path + " (" + selected + ")");
+ print_line("Editing project: " + path + " (" + selected + ")");
List<String> args;
@@ -1252,7 +1447,7 @@ void ProjectManager::_run_project_confirm() {
return;
}
- print_line("OPENING: " + path + " (" + selected + ")");
+ print_line("Running project: " + path + " (" + selected + ")");
List<String> args;
@@ -1318,13 +1513,13 @@ void ProjectManager::_scan_dir(DirAccess *da, float pos, float total, List<Strin
void ProjectManager::_scan_begin(const String &p_base) {
- print_line("SCAN PROJECTS AT: " + p_base);
+ print_line("Scanning projects at: " + p_base);
List<String> projects;
DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
da->change_dir(p_base);
_scan_dir(da, 0, 1, &projects);
memdelete(da);
- print_line("found: " + itos(projects.size()) + " projects.");
+ print_line("Found " + itos(projects.size()) + " projects.");
for (List<String>::Element *E = projects.front(); E; E = E->next()) {
String proj = E->get().replace("/", "::");
@@ -1517,19 +1712,46 @@ ProjectManager::ProjectManager() {
EditorSettings::get_singleton()->set_optimize_save(false); //just write settings as they came
{
- int dpi_mode = EditorSettings::get_singleton()->get("interface/editor/hidpi_mode");
- if (dpi_mode == 0) {
- const int screen = OS::get_singleton()->get_current_screen();
- editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
- } else if (dpi_mode == 1) {
- editor_set_scale(0.75);
- } else if (dpi_mode == 2) {
- editor_set_scale(1.0);
- } else if (dpi_mode == 3) {
- editor_set_scale(1.5);
- } else if (dpi_mode == 4) {
- editor_set_scale(2.0);
+ int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
+ float custom_display_scale = EditorSettings::get_singleton()->get("interface/editor/custom_display_scale");
+
+ switch (display_scale) {
+ case 0: {
+ // Try applying a suitable display scale automatically
+ const int screen = OS::get_singleton()->get_current_screen();
+ editor_set_scale(OS::get_singleton()->get_screen_dpi(screen) >= 192 && OS::get_singleton()->get_screen_size(screen).x > 2000 ? 2.0 : 1.0);
+ } break;
+
+ case 1: {
+ editor_set_scale(0.75);
+ } break;
+
+ case 2: {
+ editor_set_scale(1.0);
+ } break;
+
+ case 3: {
+ editor_set_scale(1.25);
+ } break;
+
+ case 4: {
+ editor_set_scale(1.5);
+ } break;
+
+ case 5: {
+ editor_set_scale(1.75);
+ } break;
+
+ case 6: {
+ editor_set_scale(2.0);
+ } break;
+
+ default: {
+ editor_set_scale(custom_display_scale);
+ } break;
}
+
+ OS::get_singleton()->set_window_size(OS::get_singleton()->get_window_size() * MAX(1, EDSCALE));
}
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
@@ -1554,8 +1776,7 @@ ProjectManager::ProjectManager() {
vb->add_constant_override("separation", 15 * EDSCALE);
String cp;
- cp.push_back(0xA9);
- cp.push_back(0);
+ cp += 0xA9;
OS::get_singleton()->set_window_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + cp + " 2007-2018 Juan Linietsky, Ariel Manzur & Godot Contributors");
HBoxContainer *top_hb = memnew(HBoxContainer);
@@ -1570,7 +1791,7 @@ ProjectManager::ProjectManager() {
String hash = String(VERSION_HASH);
if (hash.length() != 0)
hash = "." + hash.left(7);
- l->set_text("v" VERSION_MKSTRING "" + hash);
+ l->set_text("v" VERSION_FULL_BUILD "" + hash);
l->set_align(Label::ALIGN_CENTER);
top_hb->add_child(l);
@@ -1598,7 +1819,7 @@ ProjectManager::ProjectManager() {
project_filter = memnew(ProjectListFilter);
search_box->add_child(project_filter);
project_filter->connect("filter_changed", this, "_load_recent_projects");
- project_filter->set_custom_minimum_size(Size2(250, 10));
+ project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE);
search_tree_vb->add_child(search_box);
PanelContainer *pc = memnew(PanelContainer);
@@ -1796,18 +2017,6 @@ void ProjectListFilter::_setup_filters() {
filter_option->add_item(TTR("Path"));
}
-void ProjectListFilter::_command(int p_command) {
- switch (p_command) {
-
- case CMD_CLEAR_FILTER: {
- if (search_box->get_text() != "") {
- search_box->clear();
- emit_signal("filter_changed");
- }
- } break;
- }
-}
-
void ProjectListFilter::_search_text_changed(const String &p_newtext) {
emit_signal("filter_changed");
}
@@ -1830,13 +2039,14 @@ void ProjectListFilter::_filter_option_selected(int p_idx) {
void ProjectListFilter::_notification(int p_what) {
- if (p_what == NOTIFICATION_ENTER_TREE)
- clear_search_button->set_icon(get_icon("Close", "EditorIcons"));
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+ search_box->set_right_icon(get_icon("Search", "EditorIcons"));
+ search_box->set_clear_button_enabled(true);
+ }
}
void ProjectListFilter::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_command"), &ProjectListFilter::_command);
ClassDB::bind_method(D_METHOD("_search_text_changed"), &ProjectListFilter::_search_text_changed);
ClassDB::bind_method(D_METHOD("_filter_option_selected"), &ProjectListFilter::_filter_option_selected);
@@ -1861,8 +2071,4 @@ ProjectListFilter::ProjectListFilter() {
search_box->connect("text_changed", this, "_search_text_changed");
search_box->set_h_size_flags(SIZE_EXPAND_FILL);
add_child(search_box);
-
- clear_search_button = memnew(ToolButton);
- clear_search_button->connect("pressed", this, "_command", make_binds(CMD_CLEAR_FILTER));
- add_child(clear_search_button);
}