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.cpp172
1 files changed, 95 insertions, 77 deletions
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index d3def86bd1..fdd114bb1e 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -31,11 +31,11 @@
#include "project_manager.h"
#include "core/io/config_file.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
#include "core/io/resource_saver.h"
#include "core/io/stream_peer_ssl.h"
#include "core/io/zip_io.h"
-#include "core/os/dir_access.h"
-#include "core/os/file_access.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
#include "core/string/translation.h"
@@ -100,7 +100,6 @@ private:
FileDialog *fdialog_install;
String zip_path;
String zip_title;
- String zip_root;
AcceptDialog *dialog_error;
String fav_dir;
@@ -201,9 +200,7 @@ private:
char fname[16384];
ret = unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
- String fname_str = String(fname);
- if (fname_str.ends_with("project.godot")) {
- zip_root = fname_str.substr(0, fname_str.rfind("project.godot"));
+ if (String(fname).ends_with("project.godot")) {
break;
}
@@ -296,7 +293,7 @@ private:
String sp = _test_path();
if (sp != "") {
// If the project name is empty or default, infer the project name from the selected folder name
- if (project_name->get_text() == "" || project_name->get_text() == TTR("New Game Project")) {
+ if (project_name->get_text().strip_edges() == "" || project_name->get_text().strip_edges() == TTR("New Game Project")) {
sp = sp.replace("\\", "/");
int lidx = sp.rfind("/");
@@ -380,16 +377,17 @@ private:
}
void _create_folder() {
- 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);
+ const String project_name_no_edges = project_name->get_text().strip_edges();
+ if (project_name_no_edges == "" || created_folder_path != "" || project_name_no_edges.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) {
- if (!d->dir_exists(project_name->get_text())) {
- if (d->make_dir(project_name->get_text()) == OK) {
- d->change_dir(project_name->get_text());
+ if (!d->dir_exists(project_name_no_edges)) {
+ if (d->make_dir(project_name_no_edges) == OK) {
+ d->change_dir(project_name_no_edges);
String dir_str = d->get_current_dir();
project_path->set_text(dir_str);
_path_text_changed(dir_str);
@@ -415,7 +413,7 @@ private:
_test_path();
- if (p_text == "") {
+ if (p_text.strip_edges() == "") {
set_message(TTR("It would be a good idea to name your project."), MESSAGE_ERROR);
}
}
@@ -442,7 +440,7 @@ private:
set_message(vformat(TTR("Couldn't load project.godot in project path (error %d). It may be missing or corrupted."), err), MESSAGE_ERROR);
} else {
ProjectSettings::CustomMap edited_settings;
- edited_settings["application/config/name"] = project_name->get_text();
+ edited_settings["application/config/name"] = project_name->get_text().strip_edges();
if (current->save_custom(dir2.plus_file("project.godot"), edited_settings, Vector<String>(), true) != OK) {
set_message(TTR("Couldn't edit project.godot in project path."), MESSAGE_ERROR);
@@ -483,7 +481,7 @@ private:
initial_settings["rendering/textures/vram_compression/import_etc2"] = false;
initial_settings["rendering/textures/vram_compression/import_etc"] = true;
}
- initial_settings["application/config/name"] = project_name->get_text();
+ initial_settings["application/config/name"] = project_name->get_text().strip_edges();
initial_settings["application/config/icon"] = "res://icon.png";
initial_settings["rendering/environment/defaults/default_environment"] = "res://default_env.tres";
@@ -523,7 +521,24 @@ private:
return;
}
+ // Find the zip_root
+ String zip_root;
int ret = unzGoToFirstFile(pkg);
+ while (ret == UNZ_OK) {
+ unz_file_info info;
+ char fname[16384];
+ unzGetCurrentFileInfo(pkg, &info, fname, 16384, nullptr, 0, nullptr, 0);
+
+ String name = fname;
+ if (name.ends_with("project.godot")) {
+ zip_root = name.substr(0, name.rfind("project.godot"));
+ break;
+ }
+
+ ret = unzGoToNextFile(pkg);
+ }
+
+ ret = unzGoToFirstFile(pkg);
Vector<String> failed_files;
@@ -1469,16 +1484,7 @@ Vector<ProjectList::Item> ProjectList::get_selected_projects() const {
void ProjectList::ensure_project_visible(int p_index) {
const Item &item = _projects[p_index];
-
- int item_top = item.control->get_position().y;
- int item_bottom = item.control->get_position().y + item.control->get_size().y;
-
- if (item_top < get_v_scroll()) {
- set_v_scroll(item_top);
-
- } else if (item_bottom > get_v_scroll() + get_size().y) {
- set_v_scroll(item_bottom - get_size().y);
- }
+ ensure_control_visible(item.control);
}
int ProjectList::get_single_selected_index() const {
@@ -1739,7 +1745,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
const Item &clicked_project = _projects[clicked_index];
if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == MOUSE_BUTTON_LEFT) {
- if (mb->get_shift() && _selected_project_keys.size() > 0 && _last_clicked != "" && clicked_project.project_key != _last_clicked) {
+ if (mb->is_shift_pressed() && _selected_project_keys.size() > 0 && _last_clicked != "" && clicked_project.project_key != _last_clicked) {
int anchor_index = -1;
for (int i = 0; i < _projects.size(); ++i) {
const Item &p = _projects[i];
@@ -1751,7 +1757,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
CRASH_COND(anchor_index == -1);
select_range(anchor_index, clicked_index);
- } else if (mb->get_control()) {
+ } else if (mb->is_ctrl_pressed()) {
toggle_select(clicked_index);
} else {
@@ -1761,7 +1767,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
emit_signal(SIGNAL_SELECTION_CHANGED);
- if (!mb->get_control() && mb->is_doubleclick()) {
+ if (!mb->is_ctrl_pressed() && mb->is_double_click()) {
emit_signal(SIGNAL_PROJECT_ASK_OPEN);
}
}
@@ -1851,6 +1857,9 @@ void ProjectManager::_notification(int p_what) {
case NOTIFICATION_WM_CLOSE_REQUEST: {
_dim_window();
} break;
+ case NOTIFICATION_WM_ABOUT: {
+ _show_about();
+ } break;
}
}
@@ -1915,9 +1924,6 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
case KEY_ENTER: {
_open_selected_projects_ask();
} break;
- case KEY_DELETE: {
- _erase_project();
- } break;
case KEY_HOME: {
if (_project_list->get_project_count() > 0) {
_project_list->select_project(0);
@@ -1933,7 +1939,7 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
} break;
case KEY_UP: {
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
break;
}
@@ -1947,7 +1953,7 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
break;
}
case KEY_DOWN: {
- if (k->get_shift()) {
+ if (k->is_shift_pressed()) {
break;
}
@@ -1960,7 +1966,7 @@ void ProjectManager::_unhandled_key_input(const Ref<InputEvent> &p_ev) {
} break;
case KEY_F: {
- if (k->get_command()) {
+ if (k->is_command_pressed()) {
this->search_box->grab_focus();
} else {
keycode_handled = false;
@@ -2120,8 +2126,8 @@ void ProjectManager::_run_project_confirm() {
const String &selected = selected_list[i].project_key;
String path = EditorSettings::get_singleton()->get("projects/" + selected);
- // `.right(6)` on `IMPORTED_FILES_PATH` strips away the leading "res://".
- if (!DirAccess::exists(path.plus_file(ProjectSettings::IMPORTED_FILES_PATH.right(6)))) {
+ // `.substr(6)` on `IMPORTED_FILES_PATH` strips away the leading "res://".
+ if (!DirAccess::exists(path.plus_file(ProjectSettings::IMPORTED_FILES_PATH.substr(6)))) {
run_error_diag->set_text(TTR("Can't run project: Assets need to be imported.\nPlease edit the project to trigger the initial import."));
run_error_diag->popup_centered();
continue;
@@ -2254,6 +2260,10 @@ void ProjectManager::_erase_missing_projects() {
erase_missing_ask->popup_centered();
}
+void ProjectManager::_show_about() {
+ about->popup_centered(Size2(780, 500) * EDSCALE);
+}
+
void ProjectManager::_language_selected(int p_id) {
String lang = language_btn->get_item_metadata(p_id);
EditorSettings::get_singleton()->set("interface/editor/editor_language", lang);
@@ -2363,6 +2373,7 @@ void ProjectManager::_on_search_term_changed(const String &p_term) {
void ProjectManager::_bind_methods() {
ClassDB::bind_method("_unhandled_key_input", &ProjectManager::_unhandled_key_input);
ClassDB::bind_method("_update_project_buttons", &ProjectManager::_update_project_buttons);
+ ClassDB::bind_method("_version_button_pressed", &ProjectManager::_version_button_pressed);
}
void ProjectManager::_open_asset_library() {
@@ -2370,6 +2381,10 @@ void ProjectManager::_open_asset_library() {
tabs->set_current_tab(1);
}
+void ProjectManager::_version_button_pressed() {
+ DisplayServer::get_singleton()->clipboard_set(version_btn->get_text());
+}
+
ProjectManager::ProjectManager() {
// load settings
if (!EditorSettings::get_singleton()) {
@@ -2382,34 +2397,10 @@ ProjectManager::ProjectManager() {
int display_scale = EditorSettings::get_singleton()->get("interface/editor/display_scale");
switch (display_scale) {
- case 0: {
+ case 0:
// Try applying a suitable display scale automatically.
- // The code below is adapted in `editor/editor_settings.cpp` and `editor/editor_node.cpp`.
- // Make sure to update those when modifying the code below.
-#ifdef OSX_ENABLED
- editor_set_scale(DisplayServer::get_singleton()->screen_get_max_scale());
-#else
- const int screen = DisplayServer::get_singleton()->window_get_current_screen();
- float scale;
- if (DisplayServer::get_singleton()->screen_get_dpi(screen) >= 192 && DisplayServer::get_singleton()->screen_get_size(screen).y >= 1400) {
- // hiDPI display.
- scale = 2.0;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y >= 1700) {
- // Likely a hiDPI display, but we aren't certain due to the returned DPI.
- // Use an intermediate scale to handle this situation.
- scale = 1.5;
- } else if (DisplayServer::get_singleton()->screen_get_size(screen).y <= 800) {
- // Small loDPI display. Use a smaller display scale so that editor elements fit more easily.
- // Icons won't look great, but this is better than having editor elements overflow from its window.
- scale = 0.75;
- } else {
- scale = 1.0;
- }
-
- editor_set_scale(scale);
-#endif
- } break;
-
+ editor_set_scale(EditorSettings::get_singleton()->get_auto_display_scale());
+ break;
case 1:
editor_set_scale(0.75);
break;
@@ -2443,12 +2434,7 @@ ProjectManager::ProjectManager() {
}
// TRANSLATORS: This refers to the application where users manage their Godot projects.
- if (TS->is_locale_right_to_left(TranslationServer::get_singleton()->get_tool_locale())) {
- // For RTL languages, embed translated part of the title (using control characters) to ensure correct order.
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + String::chr(0x202B) + TTR("Project Manager") + String::chr(0x202C) + String::chr(0x200E) + " - " + String::chr(0xA9) + " 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors");
- } else {
- DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager") + " - " + String::chr(0xA9) + " 2007-2021 Juan Linietsky, Ariel Manzur & Godot Contributors");
- }
+ DisplayServer::get_singleton()->window_set_title(VERSION_NAME + String(" - ") + TTR("Project Manager"));
FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files"));
@@ -2477,7 +2463,7 @@ ProjectManager::ProjectManager() {
tabs->connect("tab_changed", callable_mp(this, &ProjectManager::_on_tab_changed));
HBoxContainer *projects_hb = memnew(HBoxContainer);
- projects_hb->set_name(TTR("Projects"));
+ projects_hb->set_name(TTR("Local Projects"));
tabs->add_child(projects_hb);
{
@@ -2543,16 +2529,19 @@ ProjectManager::ProjectManager() {
Button *create = memnew(Button);
create->set_text(TTR("New Project"));
+ create->set_shortcut(ED_SHORTCUT("project_manager/new_project", TTR("New Project"), KEY_MASK_CMD | KEY_N));
create->connect("pressed", callable_mp(this, &ProjectManager::_new_project));
tree_vb->add_child(create);
Button *import = memnew(Button);
import->set_text(TTR("Import"));
+ import->set_shortcut(ED_SHORTCUT("project_manager/import_project", TTR("Import Project"), KEY_MASK_CMD | KEY_I));
import->connect("pressed", callable_mp(this, &ProjectManager::_import_project));
tree_vb->add_child(import);
Button *scan = memnew(Button);
scan->set_text(TTR("Scan"));
+ scan->set_shortcut(ED_SHORTCUT("project_manager/scan_projects", TTR("Scan Projects"), KEY_MASK_CMD | KEY_S));
scan->connect("pressed", callable_mp(this, &ProjectManager::_scan_projects));
tree_vb->add_child(scan);
@@ -2560,21 +2549,25 @@ ProjectManager::ProjectManager() {
open_btn = memnew(Button);
open_btn->set_text(TTR("Edit"));
+ open_btn->set_shortcut(ED_SHORTCUT("project_manager/edit_project", TTR("Edit Project"), KEY_MASK_CMD | KEY_E));
open_btn->connect("pressed", callable_mp(this, &ProjectManager::_open_selected_projects_ask));
tree_vb->add_child(open_btn);
run_btn = memnew(Button);
run_btn->set_text(TTR("Run"));
+ run_btn->set_shortcut(ED_SHORTCUT("project_manager/run_project", TTR("Run Project"), KEY_MASK_CMD | KEY_R));
run_btn->connect("pressed", callable_mp(this, &ProjectManager::_run_project));
tree_vb->add_child(run_btn);
rename_btn = memnew(Button);
rename_btn->set_text(TTR("Rename"));
+ rename_btn->set_shortcut(ED_SHORTCUT("project_manager/rename_project", TTR("Rename Project"), KEY_F2));
rename_btn->connect("pressed", callable_mp(this, &ProjectManager::_rename_project));
tree_vb->add_child(rename_btn);
erase_btn = memnew(Button);
erase_btn->set_text(TTR("Remove"));
+ erase_btn->set_shortcut(ED_SHORTCUT("project_manager/remove_project", TTR("Remove Project"), KEY_DELETE));
erase_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_project));
tree_vb->add_child(erase_btn);
@@ -2582,6 +2575,13 @@ ProjectManager::ProjectManager() {
erase_missing_btn->set_text(TTR("Remove Missing"));
erase_missing_btn->connect("pressed", callable_mp(this, &ProjectManager::_erase_missing_projects));
tree_vb->add_child(erase_missing_btn);
+
+ tree_vb->add_spacer();
+
+ about_btn = memnew(Button);
+ about_btn->set_text(TTR("About"));
+ about_btn->connect("pressed", callable_mp(this, &ProjectManager::_show_about));
+ tree_vb->add_child(about_btn);
}
{
@@ -2591,15 +2591,30 @@ ProjectManager::ProjectManager() {
settings_hb->set_h_grow_direction(Control::GROW_DIRECTION_BEGIN);
settings_hb->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT);
- Label *version_label = memnew(Label);
+ // A VBoxContainer that contains a dummy Control node to adjust the LinkButton's vertical position.
+ VBoxContainer *spacer_vb = memnew(VBoxContainer);
+ settings_hb->add_child(spacer_vb);
+
+ Control *v_spacer = memnew(Control);
+ spacer_vb->add_child(v_spacer);
+
+ version_btn = memnew(LinkButton);
String hash = String(VERSION_HASH);
if (hash.length() != 0) {
- hash = "." + hash.left(9);
+ hash = " " + vformat("[%s]", hash.left(9));
}
- version_label->set_text("v" VERSION_FULL_BUILD "" + hash);
- version_label->set_self_modulate(Color(1, 1, 1, 0.6));
- version_label->set_align(Label::ALIGN_CENTER);
- settings_hb->add_child(version_label);
+ version_btn->set_text("v" VERSION_FULL_BUILD + hash);
+ // Fade the version label to be less prominent, but still readable.
+ version_btn->set_self_modulate(Color(1, 1, 1, 0.6));
+ version_btn->set_underline_mode(LinkButton::UNDERLINE_MODE_ON_HOVER);
+ version_btn->set_tooltip(TTR("Click to copy."));
+ version_btn->connect("pressed", callable_mp(this, &ProjectManager::_version_button_pressed));
+ spacer_vb->add_child(version_btn);
+
+ // Add a small horizontal spacer between the version and language buttons
+ // to distinguish them.
+ Control *h_spacer = memnew(Control);
+ settings_hb->add_child(h_spacer);
language_btn = memnew(OptionButton);
language_btn->set_flat(true);
@@ -2637,7 +2652,7 @@ ProjectManager::ProjectManager() {
if (StreamPeerSSL::is_available()) {
asset_library = memnew(EditorAssetLibrary(true));
- asset_library->set_name(TTR("Templates"));
+ asset_library->set_name(TTR("Asset Library Projects"));
tabs->add_child(asset_library);
asset_library->connect("install_asset", callable_mp(this, &ProjectManager::_install_project));
} else {
@@ -2715,6 +2730,9 @@ ProjectManager::ProjectManager() {
open_templates->get_ok_button()->set_text(TTR("Open Asset Library"));
open_templates->connect("confirmed", callable_mp(this, &ProjectManager::_open_asset_library));
add_child(open_templates);
+
+ about = memnew(EditorAbout);
+ add_child(about);
}
_load_recent_projects();