diff options
Diffstat (limited to 'editor/project_manager.cpp')
-rw-r--r-- | editor/project_manager.cpp | 190 |
1 files changed, 116 insertions, 74 deletions
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index ee434aaac2..23a7628eeb 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -107,9 +107,9 @@ private: 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_path_icon = status_rect->get_texture(); - Ref<Texture> current_install_icon = install_status_rect->get_texture(); - Ref<Texture> new_icon; + Ref<Texture2D> current_path_icon = status_rect->get_texture(); + Ref<Texture2D> current_install_icon = install_status_rect->get_texture(); + Ref<Texture2D> new_icon; switch (p_type) { @@ -484,8 +484,8 @@ private: if (mode == MODE_NEW) { ProjectSettings::CustomMap initial_settings; - if (rasterizer_button_group->get_pressed_button()->get_meta("driver_name") == "GLES3") { - initial_settings["rendering/quality/driver/driver_name"] = "GLES3"; + if (rasterizer_button_group->get_pressed_button()->get_meta("driver_name") == "Vulkan") { + initial_settings["rendering/quality/driver/driver_name"] = "Vulkan"; } else { initial_settings["rendering/quality/driver/driver_name"] = "GLES2"; initial_settings["rendering/vram_compression/import_etc2"] = false; @@ -811,7 +811,7 @@ public: create_dir = memnew(Button); pnhb->add_child(create_dir); create_dir->set_text(TTR("Create Folder")); - create_dir->connect("pressed", this, "_create_folder"); + create_dir->connect_compat("pressed", this, "_create_folder"); path_container = memnew(VBoxContainer); vb->add_child(path_container); @@ -848,7 +848,7 @@ public: browse = memnew(Button); browse->set_text(TTR("Browse")); - browse->connect("pressed", this, "_browse_path"); + browse->connect_compat("pressed", this, "_browse_path"); pphb->add_child(browse); // install status icon @@ -858,7 +858,7 @@ public: install_browse = memnew(Button); install_browse->set_text(TTR("Browse")); - install_browse->connect("pressed", this, "_browse_install_path"); + install_browse->connect_compat("pressed", this, "_browse_install_path"); iphb->add_child(install_browse); msg = memnew(Label); @@ -880,31 +880,46 @@ public: rshb->add_child(rvb); Button *rs_button = memnew(CheckBox); rs_button->set_button_group(rasterizer_button_group); - rs_button->set_text(TTR("OpenGL ES 3.0")); - rs_button->set_meta("driver_name", "GLES3"); + rs_button->set_text(TTR("Vulkan")); + rs_button->set_meta("driver_name", "Vulkan"); rs_button->set_pressed(true); rvb->add_child(rs_button); l = memnew(Label); - l->set_text(TTR("Higher visual quality\nAll features available\nIncompatible with older hardware\nNot recommended for web games")); + l->set_text(TTR("- Higher visual quality\n- More accurate API, which produces very fast code\n- Some features not implemented yet - work in progress\n- Incompatible with older hardware\n- Not recommended for web and mobile games")); + l->set_modulate(Color(1, 1, 1, 0.7)); rvb->add_child(l); rshb->add_child(memnew(VSeparator)); + const String gles2_unsupported_tooltip = + TTR("The GLES2 renderer is currently unavailable, as it needs to be reworked for Godot 4.0.\nUse Godot 3.2 if you need GLES2 support."); + rvb = memnew(VBoxContainer); rvb->set_h_size_flags(SIZE_EXPAND_FILL); rshb->add_child(rvb); rs_button = memnew(CheckBox); rs_button->set_button_group(rasterizer_button_group); - rs_button->set_text(TTR("OpenGL ES 2.0")); + rs_button->set_text(TTR("OpenGL ES 2.0 (currently unavailable)")); rs_button->set_meta("driver_name", "GLES2"); + rs_button->set_disabled(true); + rs_button->set_tooltip(gles2_unsupported_tooltip); rvb->add_child(rs_button); l = memnew(Label); - l->set_text(TTR("Lower visual quality\nSome features not available\nWorks on most hardware\nRecommended for web games")); + l->set_text(TTR("- Lower visual quality\n- Some features not available\n- Works on most hardware\n- Recommended for web and mobile games")); + l->set_modulate(Color(1, 1, 1, 0.7)); + // Also set the tooltip on the label so it appears when hovering either the checkbox or label. + l->set_tooltip(gles2_unsupported_tooltip); + // Required for the tooltip to show. + l->set_mouse_filter(MOUSE_FILTER_STOP); rvb->add_child(l); l = memnew(Label); - l->set_text(TTR("Renderer can be changed later, but scenes may need to be adjusted.")); + l->set_text(TTR("The renderer can be changed later, but scenes may need to be adjusted.")); + // Add some extra spacing to separate it from the list above and the buttons below. + l->set_custom_minimum_size(Size2(0, 40) * EDSCALE); l->set_align(Label::ALIGN_CENTER); + l->set_valign(Label::VALIGN_CENTER); + l->set_modulate(Color(1, 1, 1, 0.7)); rasterizer_container->add_child(l); fdialog = memnew(FileDialog); @@ -913,13 +928,13 @@ public: 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"); + project_name->connect_compat("text_changed", this, "_text_changed"); + project_path->connect_compat("text_changed", this, "_path_text_changed"); + install_path->connect_compat("text_changed", this, "_path_text_changed"); + fdialog->connect_compat("dir_selected", this, "_path_selected"); + fdialog->connect_compat("file_selected", this, "_file_selected"); + fdialog_install->connect_compat("dir_selected", this, "_install_path_selected"); + fdialog_install->connect_compat("file_selected", this, "_install_path_selected"); set_hide_on_ok(false); mode = MODE_NEW; @@ -986,7 +1001,7 @@ public: String path; String icon; String main_scene; - uint64_t last_modified; + uint64_t last_edited; bool favorite; bool grayed; bool missing; @@ -1002,7 +1017,7 @@ public: const String &p_path, const String &p_icon, const String &p_main_scene, - uint64_t p_last_modified, + uint64_t p_last_edited, bool p_favorite, bool p_grayed, bool p_missing, @@ -1014,7 +1029,7 @@ public: path = p_path; icon = p_icon; main_scene = p_main_scene; - last_modified = p_last_modified; + last_edited = p_last_edited; favorite = p_favorite; grayed = p_grayed; missing = p_missing; @@ -1037,6 +1052,7 @@ public: void sort_projects(); int get_project_count() const; void select_project(int p_index); + void select_first_visible_project(); void erase_selected_projects(); Vector<Item> get_selected_projects() const; const Set<String> &get_selected_project_keys() const; @@ -1088,8 +1104,8 @@ struct ProjectListComparator { switch (order_option) { case ProjectListFilter::FILTER_PATH: return a.project_key < b.project_key; - case ProjectListFilter::FILTER_MODIFIED: - return a.last_modified > b.last_modified; + case ProjectListFilter::FILTER_EDIT_DATE: + return a.last_edited > b.last_edited; default: return a.project_name < b.project_name; } @@ -1097,7 +1113,7 @@ struct ProjectListComparator { }; ProjectList::ProjectList() { - _order_option = ProjectListFilter::FILTER_MODIFIED; + _order_option = ProjectListFilter::FILTER_EDIT_DATE; _scroll_children = memnew(VBoxContainer); _scroll_children->set_h_size_flags(SIZE_EXPAND_FILL); @@ -1134,8 +1150,8 @@ void ProjectList::_notification(int p_what) { void ProjectList::load_project_icon(int p_index) { Item &item = _projects.write[p_index]; - Ref<Texture> default_icon = get_icon("DefaultProjectIcon", "EditorIcons"); - Ref<Texture> icon; + Ref<Texture2D> default_icon = get_icon("DefaultProjectIcon", "EditorIcons"); + Ref<Texture2D> icon; if (item.icon != "") { Ref<Image> img; img.instance(); @@ -1184,15 +1200,18 @@ void ProjectList::load_project_data(const String &p_property_key, Item &p_item, String icon = cf->get_value("application", "config/icon", ""); String main_scene = cf->get_value("application", "run/main_scene", ""); - uint64_t last_modified = 0; + uint64_t last_edited = 0; if (FileAccess::exists(conf)) { - last_modified = FileAccess::get_modified_time(conf); + // The modification date marks the date the project was last edited. + // This is because the `project.godot` file will always be modified + // when editing a project (but not when running it). + last_edited = FileAccess::get_modified_time(conf); String fscache = path.plus_file(".fscache"); if (FileAccess::exists(fscache)) { uint64_t cache_modified = FileAccess::get_modified_time(fscache); - if (cache_modified > last_modified) - last_modified = cache_modified; + if (cache_modified > last_edited) + last_edited = cache_modified; } } else { grayed = true; @@ -1202,7 +1221,7 @@ void ProjectList::load_project_data(const String &p_property_key, Item &p_item, String project_key = p_property_key.get_slice("/", 1); - p_item = Item(project_key, project_name, description, path, icon, main_scene, last_modified, p_favorite, grayed, missing, config_version); + p_item = Item(project_key, project_name, description, path, icon, main_scene, last_edited, p_favorite, grayed, missing, config_version); } void ProjectList::load_projects() { @@ -1297,12 +1316,12 @@ void ProjectList::create_project_item_control(int p_index) { Item &item = _projects.write[p_index]; ERR_FAIL_COND(item.control != NULL); // Already created - Ref<Texture> favorite_icon = get_icon("Favorites", "EditorIcons"); + Ref<Texture2D> favorite_icon = get_icon("Favorites", "EditorIcons"); Color font_color = get_color("font_color", "Tree"); ProjectListItemControl *hb = memnew(ProjectListItemControl); - hb->connect("draw", this, "_panel_draw", varray(hb)); - hb->connect("gui_input", this, "_panel_input", varray(hb)); + hb->connect_compat("draw", this, "_panel_draw", varray(hb)); + hb->connect_compat("gui_input", this, "_panel_input", varray(hb)); hb->add_constant_override("separation", 10 * EDSCALE); hb->set_tooltip(item.description); @@ -1313,7 +1332,7 @@ void ProjectList::create_project_item_control(int p_index) { favorite->set_normal_texture(favorite_icon); // This makes the project's "hover" style display correctly when hovering the favorite icon favorite->set_mouse_filter(MOUSE_FILTER_PASS); - favorite->connect("pressed", this, "_favorite_pressed", varray(hb)); + favorite->connect_compat("pressed", this, "_favorite_pressed", varray(hb)); favorite_box->add_child(favorite); favorite_box->set_alignment(BoxContainer::ALIGN_CENTER); hb->add_child(favorite_box); @@ -1361,7 +1380,7 @@ void ProjectList::create_project_item_control(int p_index) { path_hb->add_child(show); if (!item.missing) { - show->connect("pressed", this, "_show_project", varray(item.path)); + show->connect_compat("pressed", this, "_show_project", varray(item.path)); show->set_tooltip(TTR("Show in File Manager")); } else { show->set_tooltip(TTR("Error: Project is missing on the filesystem.")); @@ -1629,6 +1648,23 @@ void ProjectList::select_project(int p_index) { toggle_select(p_index); } +void ProjectList::select_first_visible_project() { + bool found = false; + + for (int i = 0; i < _projects.size(); i++) { + if (_projects[i].control->is_visible()) { + select_project(i); + found = true; + break; + } + } + + if (!found) { + // Deselect all projects if there are no visible projects in the list. + _selected_project_keys.clear(); + } +} + inline void sort(int &a, int &b) { if (a > b) { int temp = a; @@ -2291,7 +2327,7 @@ void ProjectManager::_install_project(const String &p_zip_path, const String &p_ npdialog->show_dialog(); } -void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) { +void ProjectManager::_files_dropped(PackedStringArray p_files, int p_screen) { Set<String> folders_set; DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); for (int i = 0; i < p_files.size(); i++) { @@ -2300,9 +2336,9 @@ void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) { } memdelete(da); if (folders_set.size() > 0) { - PoolStringArray folders; + PackedStringArray folders; for (Set<String>::Element *E = folders_set.front(); E; E = E->next()) { - folders.append(E->get()); + folders.push_back(E->get()); } bool confirm = true; @@ -2322,8 +2358,8 @@ void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) { memdelete(dir); } if (confirm) { - multi_scan_ask->get_ok()->disconnect("pressed", this, "_scan_multiple_folders"); - multi_scan_ask->get_ok()->connect("pressed", this, "_scan_multiple_folders", varray(folders)); + multi_scan_ask->get_ok()->disconnect_compat("pressed", this, "_scan_multiple_folders"); + multi_scan_ask->get_ok()->connect_compat("pressed", this, "_scan_multiple_folders", varray(folders)); multi_scan_ask->set_text( vformat(TTR("Are you sure to scan %s folders for existing Godot projects?\nThis could take a while."), folders.size())); multi_scan_ask->popup_centered_minsize(); @@ -2333,7 +2369,7 @@ void ProjectManager::_files_dropped(PoolStringArray p_files, int p_screen) { } } -void ProjectManager::_scan_multiple_folders(PoolStringArray p_files) { +void ProjectManager::_scan_multiple_folders(PackedStringArray p_files) { for (int i = 0; i < p_files.size(); i++) { _scan_begin(p_files.get(i)); } @@ -2347,6 +2383,12 @@ void ProjectManager::_on_order_option_changed() { void ProjectManager::_on_filter_option_changed() { _project_list->set_search_term(project_filter->get_search_term()); _project_list->sort_projects(); + + // Select the first visible project in the list. + // This makes it possible to open a project without ever touching the mouse, + // as the search field is automatically focused on startup. + _project_list->select_first_visible_project(); + _update_project_buttons(); } void ProjectManager::_bind_methods() { @@ -2476,13 +2518,13 @@ ProjectManager::ProjectManager() { Vector<String> sort_filter_titles; sort_filter_titles.push_back(TTR("Name")); sort_filter_titles.push_back(TTR("Path")); - sort_filter_titles.push_back(TTR("Last Modified")); + sort_filter_titles.push_back(TTR("Last Edited")); project_order_filter = memnew(ProjectListFilter); project_order_filter->add_filter_option(); project_order_filter->_setup_filters(sort_filter_titles); project_order_filter->set_filter_size(150); sort_filters->add_child(project_order_filter); - project_order_filter->connect("filter_changed", this, "_on_order_option_changed"); + project_order_filter->connect_compat("filter_changed", this, "_on_order_option_changed"); project_order_filter->set_custom_minimum_size(Size2(180, 10) * EDSCALE); int projects_sorting_order = (int)EditorSettings::get_singleton()->get("project_manager/sorting_order"); @@ -2492,7 +2534,7 @@ ProjectManager::ProjectManager() { project_filter = memnew(ProjectListFilter); project_filter->add_search_box(); - project_filter->connect("filter_changed", this, "_on_filter_option_changed"); + project_filter->connect_compat("filter_changed", this, "_on_filter_option_changed"); project_filter->set_custom_minimum_size(Size2(280, 10) * EDSCALE); sort_filters->add_child(project_filter); @@ -2504,8 +2546,8 @@ ProjectManager::ProjectManager() { pc->set_v_size_flags(SIZE_EXPAND_FILL); _project_list = memnew(ProjectList); - _project_list->connect(ProjectList::SIGNAL_SELECTION_CHANGED, this, "_update_project_buttons"); - _project_list->connect(ProjectList::SIGNAL_PROJECT_ASK_OPEN, this, "_open_selected_projects_ask"); + _project_list->connect_compat(ProjectList::SIGNAL_SELECTION_CHANGED, this, "_update_project_buttons"); + _project_list->connect_compat(ProjectList::SIGNAL_PROJECT_ASK_OPEN, this, "_open_selected_projects_ask"); pc->add_child(_project_list); _project_list->set_enable_h_scroll(false); @@ -2515,13 +2557,13 @@ ProjectManager::ProjectManager() { Button *open = memnew(Button); open->set_text(TTR("Edit")); tree_vb->add_child(open); - open->connect("pressed", this, "_open_selected_projects_ask"); + open->connect_compat("pressed", this, "_open_selected_projects_ask"); open_btn = open; Button *run = memnew(Button); run->set_text(TTR("Run")); tree_vb->add_child(run); - run->connect("pressed", this, "_run_project"); + run->connect_compat("pressed", this, "_run_project"); run_btn = run; tree_vb->add_child(memnew(HSeparator)); @@ -2529,7 +2571,7 @@ ProjectManager::ProjectManager() { Button *scan = memnew(Button); scan->set_text(TTR("Scan")); tree_vb->add_child(scan); - scan->connect("pressed", this, "_scan_projects"); + scan->connect_compat("pressed", this, "_scan_projects"); tree_vb->add_child(memnew(HSeparator)); @@ -2539,34 +2581,34 @@ ProjectManager::ProjectManager() { scan_dir->set_title(TTR("Select a Folder to Scan")); // must be after mode or it's overridden scan_dir->set_current_dir(EditorSettings::get_singleton()->get("filesystem/directories/default_project_path")); gui_base->add_child(scan_dir); - scan_dir->connect("dir_selected", this, "_scan_begin"); + scan_dir->connect_compat("dir_selected", this, "_scan_begin"); Button *create = memnew(Button); create->set_text(TTR("New Project")); tree_vb->add_child(create); - create->connect("pressed", this, "_new_project"); + create->connect_compat("pressed", this, "_new_project"); Button *import = memnew(Button); import->set_text(TTR("Import")); tree_vb->add_child(import); - import->connect("pressed", this, "_import_project"); + import->connect_compat("pressed", this, "_import_project"); Button *rename = memnew(Button); rename->set_text(TTR("Rename")); tree_vb->add_child(rename); - rename->connect("pressed", this, "_rename_project"); + rename->connect_compat("pressed", this, "_rename_project"); rename_btn = rename; Button *erase = memnew(Button); erase->set_text(TTR("Remove")); tree_vb->add_child(erase); - erase->connect("pressed", this, "_erase_project"); + erase->connect_compat("pressed", this, "_erase_project"); erase_btn = erase; Button *erase_missing = memnew(Button); erase_missing->set_text(TTR("Remove Missing")); tree_vb->add_child(erase_missing); - erase_missing->connect("pressed", this, "_erase_missing_projects"); + erase_missing->connect_compat("pressed", this, "_erase_missing_projects"); erase_missing_btn = erase_missing; tree_vb->add_spacer(); @@ -2575,7 +2617,7 @@ ProjectManager::ProjectManager() { asset_library = memnew(EditorAssetLibrary(true)); asset_library->set_name(TTR("Templates")); tabs->add_child(asset_library); - asset_library->connect("install_asset", this, "_install_project"); + asset_library->connect_compat("install_asset", this, "_install_project"); } else { WARN_PRINT("Asset Library not available, as it requires SSL to work."); } @@ -2622,7 +2664,7 @@ ProjectManager::ProjectManager() { language_btn->set_icon(get_icon("Environment", "EditorIcons")); settings_hb->add_child(language_btn); - language_btn->connect("item_selected", this, "_language_selected"); + language_btn->connect_compat("item_selected", this, "_language_selected"); center_box->add_child(settings_hb); settings_hb->set_anchors_and_margins_preset(Control::PRESET_TOP_RIGHT); @@ -2631,28 +2673,28 @@ ProjectManager::ProjectManager() { language_restart_ask = memnew(ConfirmationDialog); language_restart_ask->get_ok()->set_text(TTR("Restart Now")); - language_restart_ask->get_ok()->connect("pressed", this, "_restart_confirm"); + language_restart_ask->get_ok()->connect_compat("pressed", this, "_restart_confirm"); language_restart_ask->get_cancel()->set_text(TTR("Continue")); gui_base->add_child(language_restart_ask); erase_missing_ask = memnew(ConfirmationDialog); erase_missing_ask->get_ok()->set_text(TTR("Remove All")); - erase_missing_ask->get_ok()->connect("pressed", this, "_erase_missing_projects_confirm"); + erase_missing_ask->get_ok()->connect_compat("pressed", this, "_erase_missing_projects_confirm"); gui_base->add_child(erase_missing_ask); erase_ask = memnew(ConfirmationDialog); erase_ask->get_ok()->set_text(TTR("Remove")); - erase_ask->get_ok()->connect("pressed", this, "_erase_project_confirm"); + erase_ask->get_ok()->connect_compat("pressed", this, "_erase_project_confirm"); gui_base->add_child(erase_ask); multi_open_ask = memnew(ConfirmationDialog); multi_open_ask->get_ok()->set_text(TTR("Edit")); - multi_open_ask->get_ok()->connect("pressed", this, "_open_selected_projects"); + multi_open_ask->get_ok()->connect_compat("pressed", this, "_open_selected_projects"); gui_base->add_child(multi_open_ask); multi_run_ask = memnew(ConfirmationDialog); multi_run_ask->get_ok()->set_text(TTR("Run")); - multi_run_ask->get_ok()->connect("pressed", this, "_run_project_confirm"); + multi_run_ask->get_ok()->connect_compat("pressed", this, "_run_project_confirm"); gui_base->add_child(multi_run_ask); multi_scan_ask = memnew(ConfirmationDialog); @@ -2660,7 +2702,7 @@ ProjectManager::ProjectManager() { gui_base->add_child(multi_scan_ask); ask_update_settings = memnew(ConfirmationDialog); - ask_update_settings->get_ok()->connect("pressed", this, "_confirm_update_settings"); + ask_update_settings->get_ok()->connect_compat("pressed", this, "_confirm_update_settings"); gui_base->add_child(ask_update_settings); OS::get_singleton()->set_low_processor_usage_mode(true); @@ -2668,8 +2710,8 @@ ProjectManager::ProjectManager() { npdialog = memnew(ProjectDialog); gui_base->add_child(npdialog); - npdialog->connect("projects_updated", this, "_on_projects_updated"); - npdialog->connect("project_created", this, "_on_project_created"); + npdialog->connect_compat("projects_updated", this, "_on_projects_updated"); + npdialog->connect_compat("project_created", this, "_on_project_created"); _load_recent_projects(); @@ -2677,8 +2719,8 @@ ProjectManager::ProjectManager() { _scan_begin(EditorSettings::get_singleton()->get("filesystem/directories/autoscan_project_path")); } - SceneTree::get_singleton()->connect("files_dropped", this, "_files_dropped"); - SceneTree::get_singleton()->connect("global_menu_action", this, "_global_menu_action"); + SceneTree::get_singleton()->connect_compat("files_dropped", this, "_files_dropped"); + SceneTree::get_singleton()->connect_compat("global_menu_action", this, "_global_menu_action"); run_error_diag = memnew(AcceptDialog); gui_base->add_child(run_error_diag); @@ -2690,7 +2732,7 @@ ProjectManager::ProjectManager() { open_templates = memnew(ConfirmationDialog); open_templates->set_text(TTR("You currently don't have any projects.\nWould you like to explore official example projects in the Asset Library?")); open_templates->get_ok()->set_text(TTR("Open Asset Library")); - open_templates->connect("confirmed", this, "_open_asset_library"); + open_templates->connect_compat("confirmed", this, "_open_asset_library"); add_child(open_templates); } @@ -2751,14 +2793,14 @@ void ProjectListFilter::_bind_methods() { void ProjectListFilter::add_filter_option() { filter_option = memnew(OptionButton); filter_option->set_clip_text(true); - filter_option->connect("item_selected", this, "_filter_option_selected"); + filter_option->connect_compat("item_selected", this, "_filter_option_selected"); add_child(filter_option); } void ProjectListFilter::add_search_box() { search_box = memnew(LineEdit); search_box->set_placeholder(TTR("Search")); - search_box->connect("text_changed", this, "_search_text_changed"); + search_box->connect_compat("text_changed", this, "_search_text_changed"); search_box->set_h_size_flags(SIZE_EXPAND_FILL); add_child(search_box); |