2024-01-16 19:50:38 +01:00
/**************************************************************************/
/* project_dialog.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "project_dialog.h"
# include "core/config/project_settings.h"
# include "core/io/dir_access.h"
# include "core/io/zip_io.h"
# include "core/version.h"
# include "editor/editor_settings.h"
# include "editor/editor_string_names.h"
# include "editor/editor_vcs_interface.h"
# include "editor/gui/editor_file_dialog.h"
# include "editor/themes/editor_icons.h"
# include "editor/themes/editor_scale.h"
# include "scene/gui/check_box.h"
2024-02-22 14:27:04 +01:00
# include "scene/gui/check_button.h"
2024-01-16 19:50:38 +01:00
# include "scene/gui/line_edit.h"
# include "scene/gui/option_button.h"
# include "scene/gui/separator.h"
# include "scene/gui/texture_rect.h"
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _set_message ( const String & p_msg , MessageType p_type , InputType p_input_type ) {
2024-01-16 19:50:38 +01:00
msg - > set_text ( p_msg ) ;
2024-02-22 14:27:04 +01:00
get_ok_button ( ) - > set_disabled ( p_type = = MESSAGE_ERROR ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
Ref < Texture2D > new_icon ;
2024-01-16 19:50:38 +01:00
switch ( p_type ) {
case MESSAGE_ERROR : {
2024-05-14 15:57:29 +02:00
msg - > add_theme_color_override ( SceneStringName ( font_color ) , get_theme_color ( SNAME ( " error_color " ) , EditorStringName ( Editor ) ) ) ;
2024-01-16 19:50:38 +01:00
new_icon = get_editor_theme_icon ( SNAME ( " StatusError " ) ) ;
} break ;
case MESSAGE_WARNING : {
2024-05-14 15:57:29 +02:00
msg - > add_theme_color_override ( SceneStringName ( font_color ) , get_theme_color ( SNAME ( " warning_color " ) , EditorStringName ( Editor ) ) ) ;
2024-01-16 19:50:38 +01:00
new_icon = get_editor_theme_icon ( SNAME ( " StatusWarning " ) ) ;
} break ;
case MESSAGE_SUCCESS : {
2024-05-14 15:57:29 +02:00
msg - > add_theme_color_override ( SceneStringName ( font_color ) , get_theme_color ( SNAME ( " success_color " ) , EditorStringName ( Editor ) ) ) ;
2024-01-16 19:50:38 +01:00
new_icon = get_editor_theme_icon ( SNAME ( " StatusSuccess " ) ) ;
} break ;
}
2024-02-22 14:27:04 +01:00
if ( p_input_type = = PROJECT_PATH ) {
project_status_rect - > set_texture ( new_icon ) ;
} else if ( p_input_type = = INSTALL_PATH ) {
2024-01-16 19:50:38 +01:00
install_status_rect - > set_texture ( new_icon ) ;
}
}
static bool is_zip_file ( Ref < DirAccess > p_d , const String & p_path ) {
2024-02-22 14:27:04 +01:00
return p_path . get_extension ( ) = = " zip " & & p_d - > file_exists ( p_path ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _validate_path ( ) {
_set_message ( " " , MESSAGE_SUCCESS , PROJECT_PATH ) ;
_set_message ( " " , MESSAGE_SUCCESS , INSTALL_PATH ) ;
if ( project_name - > get_text ( ) . strip_edges ( ) . is_empty ( ) ) {
_set_message ( TTR ( " It would be a good idea to name your project. " ) , MESSAGE_ERROR ) ;
return ;
}
2024-01-16 19:50:38 +01:00
Ref < DirAccess > d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2024-02-22 14:27:04 +01:00
String path = project_path - > get_text ( ) . simplify_path ( ) ;
String target_path = path ;
InputType target_path_input_type = PROJECT_PATH ;
if ( mode = = MODE_IMPORT ) {
if ( path . get_file ( ) . strip_edges ( ) = = " project.godot " ) {
path = path . get_base_dir ( ) ;
project_path - > set_text ( path ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
if ( is_zip_file ( d , path ) ) {
zip_path = path ;
} else if ( is_zip_file ( d , path . strip_edges ( ) ) ) {
zip_path = path . strip_edges ( ) ;
} else {
zip_path = " " ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
if ( ! zip_path . is_empty ( ) ) {
target_path = install_path - > get_text ( ) . simplify_path ( ) ;
target_path_input_type = INSTALL_PATH ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
create_dir - > show ( ) ;
install_path_container - > show ( ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
Ref < FileAccess > io_fa ;
zlib_filefunc_def io = zipio_create_io ( & io_fa ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
unzFile pkg = unzOpen2 ( zip_path . utf8 ( ) . get_data ( ) , & io ) ;
if ( ! pkg ) {
_set_message ( TTR ( " Invalid \" .zip \" project file; it is not in ZIP format. " ) , MESSAGE_ERROR ) ;
unzClose ( pkg ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
int ret = unzGoToFirstFile ( pkg ) ;
while ( ret = = UNZ_OK ) {
unz_file_info info ;
char fname [ 16384 ] ;
ret = unzGetCurrentFileInfo ( pkg , & info , fname , 16384 , nullptr , 0 , nullptr , 0 ) ;
ERR_FAIL_COND_MSG ( ret ! = UNZ_OK , " Failed to get current file info. " ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
String name = String : : utf8 ( fname ) ;
if ( name . get_file ( ) = = " project.godot " ) {
break ; // ret == UNZ_OK.
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
ret = unzGoToNextFile ( pkg ) ;
}
if ( ret = = UNZ_END_OF_LIST_OF_FILE ) {
_set_message ( TTR ( " Invalid \" .zip \" project file; it doesn't contain a \" project.godot \" file. " ) , MESSAGE_ERROR ) ;
2024-01-16 19:50:38 +01:00
unzClose ( pkg ) ;
2024-02-22 14:27:04 +01:00
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
unzClose ( pkg ) ;
} else if ( d - > dir_exists ( path ) & & d - > file_exists ( path . path_join ( " project.godot " ) ) ) {
zip_path = " " ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
create_dir - > hide ( ) ;
install_path_container - > hide ( ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
_set_message ( TTR ( " Valid project found at path. " ) , MESSAGE_SUCCESS ) ;
} else {
create_dir - > hide ( ) ;
install_path_container - > hide ( ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
_set_message ( TTR ( " Please choose a \" project.godot \" , a directory with one, or a \" .zip \" file. " ) , MESSAGE_ERROR ) ;
return ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
}
2024-01-16 19:50:38 +01:00
2024-09-08 14:51:01 +02:00
if ( target_path . is_relative_path ( ) ) {
2024-02-22 14:27:04 +01:00
_set_message ( TTR ( " The path specified is invalid. " ) , MESSAGE_ERROR , target_path_input_type ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( target_path . get_file ( ) ! = OS : : get_singleton ( ) - > get_safe_dir_name ( target_path . get_file ( ) ) ) {
_set_message ( TTR ( " The directory name specified contains invalid characters or trailing whitespace. " ) , MESSAGE_ERROR , target_path_input_type ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
String working_dir = d - > get_current_dir ( ) ;
String executable_dir = OS : : get_singleton ( ) - > get_executable_path ( ) . get_base_dir ( ) ;
if ( target_path = = working_dir | | target_path = = executable_dir ) {
_set_message ( TTR ( " Creating a project at the engine's working directory or executable directory is not allowed, as it would prevent the project manager from starting. " ) , MESSAGE_ERROR , target_path_input_type ) ;
return ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
// TODO: The following 5 lines could be simplified if OS.get_user_home_dir() or SYSTEM_DIR_HOME is implemented. See: https://github.com/godotengine/godot-proposals/issues/4851.
# ifdef WINDOWS_ENABLED
String home_dir = OS : : get_singleton ( ) - > get_environment ( " USERPROFILE " ) ;
# else
String home_dir = OS : : get_singleton ( ) - > get_environment ( " HOME " ) ;
# endif
String documents_dir = OS : : get_singleton ( ) - > get_system_dir ( OS : : SYSTEM_DIR_DOCUMENTS ) ;
if ( target_path = = home_dir | | target_path = = documents_dir ) {
_set_message ( TTR ( " You cannot save a project at the selected path. Please create a subfolder or choose a new path. " ) , MESSAGE_ERROR , target_path_input_type ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
is_folder_empty = true ;
if ( mode = = MODE_NEW | | mode = = MODE_INSTALL | | ( mode = = MODE_IMPORT & & target_path_input_type = = InputType : : INSTALL_PATH ) ) {
if ( create_dir - > is_pressed ( ) ) {
if ( ! d - > dir_exists ( target_path . get_base_dir ( ) ) ) {
_set_message ( TTR ( " The parent directory of the path specified doesn't exist. " ) , MESSAGE_ERROR , target_path_input_type ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( d - > dir_exists ( target_path ) ) {
// The path is not necessarily empty here, but we will update the message later if it isn't.
_set_message ( TTR ( " The project folder already exists and is empty. " ) , MESSAGE_SUCCESS , target_path_input_type ) ;
} else {
_set_message ( TTR ( " The project folder will be automatically created. " ) , MESSAGE_SUCCESS , target_path_input_type ) ;
}
} else {
if ( ! d - > dir_exists ( target_path ) ) {
_set_message ( TTR ( " The path specified doesn't exist. " ) , MESSAGE_ERROR , target_path_input_type ) ;
return ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
// The path is not necessarily empty here, but we will update the message later if it isn't.
_set_message ( TTR ( " The project folder exists and is empty. " ) , MESSAGE_SUCCESS , target_path_input_type ) ;
}
// Check if the directory is empty. Not an error, but we want to warn the user.
if ( d - > change_dir ( target_path ) = = OK ) {
d - > list_dir_begin ( ) ;
String n = d - > get_next ( ) ;
while ( ! n . is_empty ( ) ) {
if ( n [ 0 ] ! = ' . ' ) {
// Allow `.`, `..` (reserved current/parent folder names)
// and hidden files/folders to be present.
// For instance, this lets users initialize a Git repository
// and still be able to create a project in the directory afterwards.
is_folder_empty = false ;
break ;
}
n = d - > get_next ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
d - > list_dir_end ( ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( ! is_folder_empty ) {
_set_message ( TTR ( " The selected path is not empty. Choosing an empty folder is highly recommended. " ) , MESSAGE_WARNING , target_path_input_type ) ;
}
2024-01-16 19:50:38 +01:00
}
}
2024-02-22 14:27:04 +01:00
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
String ProjectDialog : : _get_target_path ( ) {
if ( mode = = MODE_NEW | | mode = = MODE_INSTALL ) {
return project_path - > get_text ( ) ;
} else if ( mode = = MODE_IMPORT ) {
return install_path - > get_text ( ) ;
} else {
ERR_FAIL_V ( " " ) ;
2024-01-16 19:50:38 +01:00
}
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _set_target_path ( const String & p_text ) {
if ( mode = = MODE_NEW | | mode = = MODE_INSTALL ) {
project_path - > set_text ( p_text ) ;
} else if ( mode = = MODE_IMPORT ) {
install_path - > set_text ( p_text ) ;
2024-01-16 19:50:38 +01:00
} else {
2024-02-22 14:27:04 +01:00
ERR_FAIL ( ) ;
}
}
void ProjectDialog : : _update_target_auto_dir ( ) {
String new_auto_dir ;
if ( mode = = MODE_NEW | | mode = = MODE_INSTALL ) {
new_auto_dir = project_name - > get_text ( ) ;
} else if ( mode = = MODE_IMPORT ) {
new_auto_dir = project_path - > get_text ( ) . get_file ( ) . get_basename ( ) ;
}
int naming_convention = ( int ) EDITOR_GET ( " project_manager/directory_naming_convention " ) ;
switch ( naming_convention ) {
case 0 : // No convention
break ;
case 1 : // kebab-case
new_auto_dir = new_auto_dir . to_lower ( ) . replace ( " " , " - " ) ;
break ;
case 2 : // snake_case
new_auto_dir = new_auto_dir . to_snake_case ( ) ;
break ;
case 3 : // camelCase
new_auto_dir = new_auto_dir . to_camel_case ( ) ;
break ;
case 4 : // PascalCase
new_auto_dir = new_auto_dir . to_pascal_case ( ) ;
break ;
case 5 : // Title Case
new_auto_dir = new_auto_dir . capitalize ( ) ;
break ;
default :
ERR_FAIL_MSG ( " Invalid directory naming convention. " ) ;
break ;
}
new_auto_dir = OS : : get_singleton ( ) - > get_safe_dir_name ( new_auto_dir ) ;
if ( create_dir - > is_pressed ( ) ) {
String target_path = _get_target_path ( ) ;
if ( target_path . get_file ( ) = = auto_dir ) {
// Update target dir name to new project name / ZIP name.
target_path = target_path . get_base_dir ( ) . path_join ( new_auto_dir ) ;
}
_set_target_path ( target_path ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
auto_dir = new_auto_dir ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _create_dir_toggled ( bool p_pressed ) {
String target_path = _get_target_path ( ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( create_dir - > is_pressed ( ) ) {
// (Re-)append target dir name.
if ( last_custom_target_dir . is_empty ( ) ) {
target_path = target_path . path_join ( auto_dir ) ;
2024-01-16 19:50:38 +01:00
} else {
2024-02-22 14:27:04 +01:00
target_path = target_path . path_join ( last_custom_target_dir ) ;
}
} else {
2024-07-07 00:49:33 +02:00
// Strip any trailing slash.
target_path = target_path . rstrip ( " / \\ " ) ;
2024-02-22 14:27:04 +01:00
// Save and remove target dir name.
if ( target_path . get_file ( ) = = auto_dir ) {
last_custom_target_dir = " " ;
} else {
last_custom_target_dir = target_path . get_file ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
target_path = target_path . get_base_dir ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
_set_target_path ( target_path ) ;
_validate_path ( ) ;
}
void ProjectDialog : : _project_name_changed ( ) {
if ( mode = = MODE_NEW | | mode = = MODE_INSTALL ) {
_update_target_auto_dir ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
_validate_path ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _project_path_changed ( ) {
if ( mode = = MODE_IMPORT ) {
_update_target_auto_dir ( ) ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
_validate_path ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _install_path_changed ( ) {
_validate_path ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _browse_project_path ( ) {
2024-08-02 23:49:25 +02:00
String path = project_path - > get_text ( ) ;
2024-09-08 14:51:01 +02:00
if ( path . is_relative_path ( ) ) {
2024-08-02 23:49:25 +02:00
path = EDITOR_GET ( " filesystem/directories/default_project_path " ) ;
}
2024-02-22 14:27:04 +01:00
if ( mode = = MODE_IMPORT & & install_path - > is_visible_in_tree ( ) ) {
// Select last ZIP file.
2024-08-02 23:49:25 +02:00
fdialog_project - > set_current_path ( path ) ;
2024-02-22 14:27:04 +01:00
} else if ( ( mode = = MODE_NEW | | mode = = MODE_INSTALL ) & & create_dir - > is_pressed ( ) ) {
// Select parent directory of project path.
2024-08-02 23:49:25 +02:00
fdialog_project - > set_current_dir ( path . get_base_dir ( ) ) ;
2024-02-22 14:27:04 +01:00
} else {
// Select project path.
2024-08-02 23:49:25 +02:00
fdialog_project - > set_current_dir ( path ) ;
2024-02-22 14:27:04 +01:00
}
2024-01-16 19:50:38 +01:00
if ( mode = = MODE_IMPORT ) {
2024-02-22 14:27:04 +01:00
fdialog_project - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_ANY ) ;
fdialog_project - > clear_filters ( ) ;
fdialog_project - > add_filter ( " project.godot " , vformat ( " %s %s " , VERSION_NAME , TTR ( " Project " ) ) ) ;
fdialog_project - > add_filter ( " *.zip " , TTR ( " ZIP File " ) ) ;
2024-01-16 19:50:38 +01:00
} else {
2024-02-22 14:27:04 +01:00
fdialog_project - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_DIR ) ;
2024-01-16 19:50:38 +01:00
}
2024-08-02 14:02:19 +02:00
hide ( ) ;
2024-02-22 14:27:04 +01:00
fdialog_project - > popup_file_dialog ( ) ;
2024-01-16 19:50:38 +01:00
}
void ProjectDialog : : _browse_install_path ( ) {
2024-02-22 14:27:04 +01:00
ERR_FAIL_COND_MSG ( mode ! = MODE_IMPORT , " Install path is only used for MODE_IMPORT. " ) ;
2024-09-08 14:51:01 +02:00
String path = install_path - > get_text ( ) ;
if ( path . is_relative_path ( ) | | ! DirAccess : : dir_exists_absolute ( path ) ) {
path = EDITOR_GET ( " filesystem/directories/default_project_path " ) ;
}
2024-02-22 14:27:04 +01:00
if ( create_dir - > is_pressed ( ) ) {
// Select parent directory of install path.
2024-09-08 14:51:01 +02:00
fdialog_install - > set_current_dir ( path . get_base_dir ( ) ) ;
2024-02-22 14:27:04 +01:00
} else {
// Select install path.
2024-09-08 14:51:01 +02:00
fdialog_install - > set_current_dir ( path ) ;
2024-02-22 14:27:04 +01:00
}
2024-01-16 19:50:38 +01:00
fdialog_install - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_DIR ) ;
fdialog_install - > popup_file_dialog ( ) ;
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _project_path_selected ( const String & p_path ) {
2024-08-02 14:02:19 +02:00
show_dialog ( false ) ;
2024-07-19 14:57:16 +02:00
2024-02-22 14:27:04 +01:00
if ( create_dir - > is_pressed ( ) & & ( mode = = MODE_NEW | | mode = = MODE_INSTALL ) ) {
// Replace parent directory, but keep target dir name.
project_path - > set_text ( p_path . path_join ( project_path - > get_text ( ) . get_file ( ) ) ) ;
} else {
project_path - > set_text ( p_path ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
_project_path_changed ( ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( install_path - > is_visible_in_tree ( ) ) {
// ZIP is selected; focus install path.
install_path - > grab_focus ( ) ;
} else {
get_ok_button ( ) - > grab_focus ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _install_path_selected ( const String & p_path ) {
ERR_FAIL_COND_MSG ( mode ! = MODE_IMPORT , " Install path is only used for MODE_IMPORT. " ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( create_dir - > is_pressed ( ) ) {
// Replace parent directory, but keep target dir name.
install_path - > set_text ( p_path . path_join ( install_path - > get_text ( ) . get_file ( ) ) ) ;
} else {
install_path - > set_text ( p_path ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
_install_path_changed ( ) ;
get_ok_button ( ) - > grab_focus ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-08-07 13:22:55 +02:00
void ProjectDialog : : _reset_name ( ) {
project_name - > set_text ( TTR ( " New Game Project " ) ) ;
}
2024-01-16 19:50:38 +01:00
void ProjectDialog : : _renderer_selected ( ) {
ERR_FAIL_NULL ( renderer_button_group - > get_pressed_button ( ) ) ;
String renderer_type = renderer_button_group - > get_pressed_button ( ) - > get_meta ( SNAME ( " rendering_method " ) ) ;
2024-04-25 19:37:38 +02:00
bool rd_error = false ;
2024-01-16 19:50:38 +01:00
if ( renderer_type = = " forward_plus " ) {
renderer_info - > set_text (
String : : utf8 ( " • " ) + TTR ( " Supports desktop platforms only. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Advanced 3D graphics available. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Can scale to large complex scenes. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Uses RenderingDevice backend. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Slower rendering of simple scenes. " ) ) ;
2024-04-25 19:37:38 +02:00
rd_error = ! rendering_device_supported ;
2024-01-16 19:50:38 +01:00
} else if ( renderer_type = = " mobile " ) {
renderer_info - > set_text (
String : : utf8 ( " • " ) + TTR ( " Supports desktop + mobile platforms. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Less advanced 3D graphics. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Less scalable for complex scenes. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Uses RenderingDevice backend. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Fast rendering of simple scenes. " ) ) ;
2024-04-25 19:37:38 +02:00
rd_error = ! rendering_device_supported ;
2024-01-16 19:50:38 +01:00
} else if ( renderer_type = = " gl_compatibility " ) {
renderer_info - > set_text (
String : : utf8 ( " • " ) + TTR ( " Supports desktop, mobile + web platforms. " ) +
2024-04-25 19:37:38 +02:00
String : : utf8 ( " \n • " ) + TTR ( " Least advanced 3D graphics. " ) +
2024-01-16 19:50:38 +01:00
String : : utf8 ( " \n • " ) + TTR ( " Intended for low-end/older devices. " ) +
String : : utf8 ( " \n • " ) + TTR ( " Uses OpenGL 3 backend (OpenGL 3.3/ES 3.0/WebGL2). " ) +
String : : utf8 ( " \n • " ) + TTR ( " Fastest rendering of simple scenes. " ) ) ;
} else {
WARN_PRINT ( " Unknown renderer type. Please report this as a bug on GitHub. " ) ;
}
2024-04-25 19:37:38 +02:00
rd_not_supported - > set_visible ( rd_error ) ;
get_ok_button ( ) - > set_disabled ( rd_error ) ;
if ( rd_error ) {
// Needs to be set here since theme colors aren't available at startup.
rd_not_supported - > add_theme_color_override ( SceneStringName ( font_color ) , get_theme_color ( SNAME ( " error_color " ) , EditorStringName ( Editor ) ) ) ;
}
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : _nonempty_confirmation_ok_pressed ( ) {
is_folder_empty = true ;
ok_pressed ( ) ;
2024-01-16 19:50:38 +01:00
}
void ProjectDialog : : ok_pressed ( ) {
2024-02-22 14:27:04 +01:00
// Before we create a project, check that the target folder is empty.
// If not, we need to ask the user if they're sure they want to do this.
if ( ! is_folder_empty ) {
ConfirmationDialog * cd = memnew ( ConfirmationDialog ) ;
cd - > set_title ( TTR ( " Warning: This folder is not empty " ) ) ;
cd - > set_text ( TTR ( " You are about to create a Godot project in a non-empty folder. \n The entire contents of this folder will be imported as project resources! \n \n Are you sure you wish to continue? " ) ) ;
2024-05-14 09:40:21 +02:00
cd - > get_ok_button ( ) - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ProjectDialog : : _nonempty_confirmation_ok_pressed ) ) ;
2024-02-22 14:27:04 +01:00
get_parent ( ) - > add_child ( cd ) ;
cd - > popup_centered ( ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
String path = project_path - > get_text ( ) ;
if ( mode = = MODE_NEW ) {
if ( create_dir - > is_pressed ( ) ) {
Ref < DirAccess > d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
if ( ! d - > dir_exists ( path ) & & d - > make_dir ( path ) ! = OK ) {
_set_message ( TTR ( " Couldn't create project directory, check permissions. " ) , MESSAGE_ERROR ) ;
return ;
}
}
PackedStringArray project_features = ProjectSettings : : get_required_features ( ) ;
ProjectSettings : : CustomMap initial_settings ;
// Be sure to change this code if/when renderers are changed.
// Default values are "forward_plus" for the main setting, "mobile" for the mobile override,
// and "gl_compatibility" for the web override.
String renderer_type = renderer_button_group - > get_pressed_button ( ) - > get_meta ( SNAME ( " rendering_method " ) ) ;
initial_settings [ " rendering/renderer/rendering_method " ] = renderer_type ;
EditorSettings : : get_singleton ( ) - > set ( " project_manager/default_renderer " , renderer_type ) ;
EditorSettings : : get_singleton ( ) - > save ( ) ;
if ( renderer_type = = " forward_plus " ) {
project_features . push_back ( " Forward Plus " ) ;
} else if ( renderer_type = = " mobile " ) {
project_features . push_back ( " Mobile " ) ;
} else if ( renderer_type = = " gl_compatibility " ) {
project_features . push_back ( " GL Compatibility " ) ;
// Also change the default rendering method for the mobile override.
initial_settings [ " rendering/renderer/rendering_method.mobile " ] = " gl_compatibility " ;
} else {
WARN_PRINT ( " Unknown renderer type. Please report this as a bug on GitHub. " ) ;
}
project_features . sort ( ) ;
initial_settings [ " application/config/features " ] = project_features ;
initial_settings [ " application/config/name " ] = project_name - > get_text ( ) . strip_edges ( ) ;
initial_settings [ " application/config/icon " ] = " res://icon.svg " ;
Error err = ProjectSettings : : get_singleton ( ) - > save_custom ( path . path_join ( " project.godot " ) , initial_settings , Vector < String > ( ) , false ) ;
if ( err ! = OK ) {
_set_message ( TTR ( " Couldn't create project.godot in project path. " ) , MESSAGE_ERROR ) ;
2024-01-16 19:50:38 +01:00
return ;
}
2024-02-22 14:27:04 +01:00
// Store default project icon in SVG format.
Ref < FileAccess > fa_icon = FileAccess : : open ( path . path_join ( " icon.svg " ) , FileAccess : : WRITE , & err ) ;
2024-01-16 19:50:38 +01:00
if ( err ! = OK ) {
2024-02-22 14:27:04 +01:00
_set_message ( TTR ( " Couldn't create icon.svg in project path. " ) , MESSAGE_ERROR ) ;
return ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
fa_icon - > store_string ( get_default_project_icon ( ) ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
EditorVCSInterface : : create_vcs_metadata_files ( EditorVCSInterface : : VCSMetadata ( vcs_metadata_selection - > get_selected ( ) ) , path ) ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
// Two cases for importing a ZIP.
switch ( mode ) {
case MODE_IMPORT : {
if ( zip_path . is_empty ( ) ) {
break ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
path = install_path - > get_text ( ) . simplify_path ( ) ;
[[fallthrough]] ;
}
case MODE_INSTALL : {
ERR_FAIL_COND ( zip_path . is_empty ( ) ) ;
Ref < FileAccess > io_fa ;
zlib_filefunc_def io = zipio_create_io ( & io_fa ) ;
unzFile pkg = unzOpen2 ( zip_path . utf8 ( ) . get_data ( ) , & io ) ;
if ( ! pkg ) {
dialog_error - > set_text ( TTR ( " Error opening package file, not in ZIP format. " ) ) ;
dialog_error - > popup_centered ( ) ;
2024-01-16 19:50:38 +01:00
return ;
}
2024-02-22 14:27:04 +01:00
// Find the first directory with a "project.godot".
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 ) ;
ERR_FAIL_COND_MSG ( ret ! = UNZ_OK , " Failed to get current file info. " ) ;
String name = String : : utf8 ( fname ) ;
if ( name . get_file ( ) = = " project.godot " ) {
zip_root = name . get_base_dir ( ) ;
break ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
ret = unzGoToNextFile ( pkg ) ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( ret = = UNZ_END_OF_LIST_OF_FILE ) {
_set_message ( TTR ( " Invalid \" .zip \" project file; it doesn't contain a \" project.godot \" file. " ) , MESSAGE_ERROR ) ;
unzClose ( pkg ) ;
return ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( create_dir - > is_pressed ( ) ) {
Ref < DirAccess > d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
if ( ! d - > dir_exists ( path ) & & d - > make_dir ( path ) ! = OK ) {
_set_message ( TTR ( " Couldn't create project directory, check permissions. " ) , MESSAGE_ERROR ) ;
2024-01-16 19:50:38 +01:00
return ;
}
2024-02-22 14:27:04 +01:00
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
ret = unzGoToFirstFile ( pkg ) ;
Vector < String > failed_files ;
while ( ret = = UNZ_OK ) {
//get filename
unz_file_info info ;
char fname [ 16384 ] ;
ret = unzGetCurrentFileInfo ( pkg , & info , fname , 16384 , nullptr , 0 , nullptr , 0 ) ;
ERR_FAIL_COND_MSG ( ret ! = UNZ_OK , " Failed to get current file info. " ) ;
String rel_path = String : : utf8 ( fname ) . trim_prefix ( zip_root ) ;
if ( rel_path . is_empty ( ) ) { // Root.
} else if ( rel_path . ends_with ( " / " ) ) { // Directory.
Ref < DirAccess > da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
da - > make_dir ( path . path_join ( rel_path ) ) ;
} else { // File.
Vector < uint8_t > uncomp_data ;
uncomp_data . resize ( info . uncompressed_size ) ;
unzOpenCurrentFile ( pkg ) ;
ret = unzReadCurrentFile ( pkg , uncomp_data . ptrw ( ) , uncomp_data . size ( ) ) ;
ERR_BREAK_MSG ( ret < 0 , vformat ( " An error occurred while attempting to read from file: %s. This file will not be used. " , rel_path ) ) ;
unzCloseCurrentFile ( pkg ) ;
Ref < FileAccess > f = FileAccess : : open ( path . path_join ( rel_path ) , FileAccess : : WRITE ) ;
if ( f . is_valid ( ) ) {
f - > store_buffer ( uncomp_data . ptr ( ) , uncomp_data . size ( ) ) ;
} else {
failed_files . push_back ( rel_path ) ;
2024-01-16 19:50:38 +01:00
}
}
2024-02-22 14:27:04 +01:00
ret = unzGoToNextFile ( pkg ) ;
}
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
unzClose ( pkg ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
if ( failed_files . size ( ) ) {
String err_msg = TTR ( " The following files failed extraction from package: " ) + " \n \n " ;
for ( int i = 0 ; i < failed_files . size ( ) ; i + + ) {
if ( i > 15 ) {
err_msg + = " \n And " + itos ( failed_files . size ( ) - i ) + " more files. " ;
2024-01-16 19:50:38 +01:00
break ;
}
2024-02-22 14:27:04 +01:00
err_msg + = failed_files [ i ] + " \n " ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
dialog_error - > set_text ( err_msg ) ;
dialog_error - > popup_centered ( ) ;
return ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
} break ;
default : {
} break ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
if ( mode = = MODE_RENAME | | mode = = MODE_INSTALL ) {
// Load project.godot as ConfigFile to set the new name.
ConfigFile cfg ;
String project_godot = path . path_join ( " project.godot " ) ;
Error err = cfg . load ( project_godot ) ;
if ( err ! = OK ) {
dialog_error - > set_text ( vformat ( TTR ( " Couldn't load project at '%s' (error %d). It may be missing or corrupted. " ) , project_godot , err ) ) ;
dialog_error - > popup_centered ( ) ;
return ;
}
cfg . set_value ( " application " , " config/name " , project_name - > get_text ( ) . strip_edges ( ) ) ;
err = cfg . save ( project_godot ) ;
if ( err ! = OK ) {
dialog_error - > set_text ( vformat ( TTR ( " Couldn't save project at '%s' (error %d). " ) , project_godot , err ) ) ;
dialog_error - > popup_centered ( ) ;
return ;
}
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
hide ( ) ;
if ( mode = = MODE_NEW | | mode = = MODE_IMPORT | | mode = = MODE_INSTALL ) {
emit_signal ( SNAME ( " project_created " ) , path ) ;
} else if ( mode = = MODE_RENAME ) {
emit_signal ( SNAME ( " projects_updated " ) ) ;
2024-01-16 19:50:38 +01:00
}
}
void ProjectDialog : : set_zip_path ( const String & p_path ) {
zip_path = p_path ;
}
void ProjectDialog : : set_zip_title ( const String & p_title ) {
zip_title = p_title ;
}
void ProjectDialog : : set_mode ( Mode p_mode ) {
mode = p_mode ;
}
2024-02-22 14:27:04 +01:00
void ProjectDialog : : set_project_name ( const String & p_name ) {
project_name - > set_text ( p_name ) ;
}
2024-01-16 19:50:38 +01:00
void ProjectDialog : : set_project_path ( const String & p_path ) {
project_path - > set_text ( p_path ) ;
}
void ProjectDialog : : ask_for_path_and_show ( ) {
2024-08-07 13:22:55 +02:00
_reset_name ( ) ;
2024-02-22 14:27:04 +01:00
_browse_project_path ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-08-02 14:02:19 +02:00
void ProjectDialog : : show_dialog ( bool p_reset_name ) {
2024-01-16 19:50:38 +01:00
if ( mode = = MODE_RENAME ) {
2024-02-22 14:27:04 +01:00
// Name and path are set in `ProjectManager::_rename_project`.
2024-01-16 19:50:38 +01:00
project_path - > set_editable ( false ) ;
set_title ( TTR ( " Rename Project " ) ) ;
set_ok_button_text ( TTR ( " Rename " ) ) ;
2024-02-22 14:27:04 +01:00
create_dir - > hide ( ) ;
project_status_rect - > hide ( ) ;
project_browse - > hide ( ) ;
2024-01-16 19:50:38 +01:00
name_container - > show ( ) ;
install_path_container - > hide ( ) ;
renderer_container - > hide ( ) ;
default_files_container - > hide ( ) ;
callable_mp ( ( Control * ) project_name , & Control : : grab_focus ) . call_deferred ( ) ;
2024-02-22 14:27:04 +01:00
callable_mp ( project_name , & LineEdit : : select_all ) . call_deferred ( ) ;
2024-01-16 19:50:38 +01:00
} else {
2024-08-02 14:02:19 +02:00
if ( p_reset_name ) {
2024-08-07 13:22:55 +02:00
_reset_name ( ) ;
2024-08-02 14:02:19 +02:00
}
2024-02-22 14:27:04 +01:00
project_path - > set_editable ( true ) ;
String fav_dir = EDITOR_GET ( " filesystem/directories/default_project_path " ) ;
2024-01-16 19:50:38 +01:00
if ( ! fav_dir . is_empty ( ) ) {
project_path - > set_text ( fav_dir ) ;
2024-02-22 14:27:04 +01:00
install_path - > set_text ( fav_dir ) ;
fdialog_project - > set_current_dir ( fav_dir ) ;
2024-01-16 19:50:38 +01:00
} else {
Ref < DirAccess > d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
project_path - > set_text ( d - > get_current_dir ( ) ) ;
2024-02-22 14:27:04 +01:00
install_path - > set_text ( d - > get_current_dir ( ) ) ;
fdialog_project - > set_current_dir ( d - > get_current_dir ( ) ) ;
2024-01-16 19:50:38 +01:00
}
create_dir - > show ( ) ;
2024-02-22 14:27:04 +01:00
project_status_rect - > show ( ) ;
project_browse - > show ( ) ;
2024-01-16 19:50:38 +01:00
if ( mode = = MODE_IMPORT ) {
set_title ( TTR ( " Import Existing Project " ) ) ;
set_ok_button_text ( TTR ( " Import & Edit " ) ) ;
2024-02-22 14:27:04 +01:00
2024-01-16 19:50:38 +01:00
name_container - > hide ( ) ;
install_path_container - > hide ( ) ;
renderer_container - > hide ( ) ;
default_files_container - > hide ( ) ;
2024-02-22 14:27:04 +01:00
// Project path dialog is also opened; no need to change focus.
2024-01-16 19:50:38 +01:00
} else if ( mode = = MODE_NEW ) {
set_title ( TTR ( " Create New Project " ) ) ;
set_ok_button_text ( TTR ( " Create & Edit " ) ) ;
2024-02-22 14:27:04 +01:00
2024-01-16 19:50:38 +01:00
name_container - > show ( ) ;
install_path_container - > hide ( ) ;
renderer_container - > show ( ) ;
default_files_container - > show ( ) ;
2024-02-22 14:27:04 +01:00
2024-01-16 19:50:38 +01:00
callable_mp ( ( Control * ) project_name , & Control : : grab_focus ) . call_deferred ( ) ;
callable_mp ( project_name , & LineEdit : : select_all ) . call_deferred ( ) ;
} else if ( mode = = MODE_INSTALL ) {
set_title ( TTR ( " Install Project: " ) + " " + zip_title ) ;
set_ok_button_text ( TTR ( " Install & Edit " ) ) ;
2024-02-22 14:27:04 +01:00
2024-01-16 19:50:38 +01:00
project_name - > set_text ( zip_title ) ;
2024-02-22 14:27:04 +01:00
2024-01-16 19:50:38 +01:00
name_container - > show ( ) ;
install_path_container - > hide ( ) ;
renderer_container - > hide ( ) ;
default_files_container - > hide ( ) ;
2024-02-22 14:27:04 +01:00
callable_mp ( ( Control * ) project_path , & Control : : grab_focus ) . call_deferred ( ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
auto_dir = " " ;
last_custom_target_dir = " " ;
_update_target_auto_dir ( ) ;
if ( create_dir - > is_pressed ( ) ) {
// Append `auto_dir` to target path.
_create_dir_toggled ( true ) ;
}
2024-01-16 19:50:38 +01:00
}
2024-02-22 14:27:04 +01:00
_validate_path ( ) ;
2024-03-07 03:36:44 +01:00
2024-02-22 14:27:04 +01:00
popup_centered ( Size2 ( 500 , 0 ) * EDSCALE ) ;
2024-01-16 19:50:38 +01:00
}
2024-02-25 19:10:29 +01:00
void ProjectDialog : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_THEME_CHANGED : {
create_dir - > set_icon ( get_editor_theme_icon ( SNAME ( " FolderCreate " ) ) ) ;
project_browse - > set_icon ( get_editor_theme_icon ( SNAME ( " FolderBrowse " ) ) ) ;
install_browse - > set_icon ( get_editor_theme_icon ( SNAME ( " FolderBrowse " ) ) ) ;
} break ;
2024-07-19 14:57:16 +02:00
case NOTIFICATION_READY : {
fdialog_project = memnew ( EditorFileDialog ) ;
fdialog_project - > set_previews_enabled ( false ) ; // Crucial, otherwise the engine crashes.
fdialog_project - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
fdialog_project - > connect ( " dir_selected " , callable_mp ( this , & ProjectDialog : : _project_path_selected ) ) ;
fdialog_project - > connect ( " file_selected " , callable_mp ( this , & ProjectDialog : : _project_path_selected ) ) ;
2024-08-02 14:02:19 +02:00
fdialog_project - > connect ( " canceled " , callable_mp ( this , & ProjectDialog : : show_dialog ) . bind ( false ) , CONNECT_DEFERRED ) ;
2024-07-19 14:57:16 +02:00
callable_mp ( ( Node * ) this , & Node : : add_sibling ) . call_deferred ( fdialog_project , false ) ;
} break ;
2024-02-25 19:10:29 +01:00
}
}
2024-01-16 19:50:38 +01:00
void ProjectDialog : : _bind_methods ( ) {
ADD_SIGNAL ( MethodInfo ( " project_created " ) ) ;
ADD_SIGNAL ( MethodInfo ( " projects_updated " ) ) ;
}
ProjectDialog : : ProjectDialog ( ) {
VBoxContainer * vb = memnew ( VBoxContainer ) ;
add_child ( vb ) ;
name_container = memnew ( VBoxContainer ) ;
vb - > add_child ( name_container ) ;
Label * l = memnew ( Label ) ;
l - > set_text ( TTR ( " Project Name: " ) ) ;
name_container - > add_child ( l ) ;
project_name = memnew ( LineEdit ) ;
project_name - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2024-02-22 14:27:04 +01:00
name_container - > add_child ( project_name ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
project_path_container = memnew ( VBoxContainer ) ;
vb - > add_child ( project_path_container ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
HBoxContainer * pphb_label = memnew ( HBoxContainer ) ;
project_path_container - > add_child ( pphb_label ) ;
2024-01-16 19:50:38 +01:00
l = memnew ( Label ) ;
l - > set_text ( TTR ( " Project Path: " ) ) ;
2024-02-22 14:27:04 +01:00
l - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
pphb_label - > add_child ( l ) ;
create_dir = memnew ( CheckButton ) ;
create_dir - > set_text ( TTR ( " Create Folder " ) ) ;
create_dir - > set_pressed ( true ) ;
pphb_label - > add_child ( create_dir ) ;
2024-06-01 12:15:13 +02:00
create_dir - > connect ( SceneStringName ( toggled ) , callable_mp ( this , & ProjectDialog : : _create_dir_toggled ) ) ;
2024-01-16 19:50:38 +01:00
HBoxContainer * pphb = memnew ( HBoxContainer ) ;
2024-02-22 14:27:04 +01:00
project_path_container - > add_child ( pphb ) ;
2024-01-16 19:50:38 +01:00
project_path = memnew ( LineEdit ) ;
project_path - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
project_path - > set_structured_text_bidi_override ( TextServer : : STRUCTURED_TEXT_FILE ) ;
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 ( Control : : SIZE_EXPAND_FILL ) ;
install_path - > set_structured_text_bidi_override ( TextServer : : STRUCTURED_TEXT_FILE ) ;
iphb - > add_child ( install_path ) ;
// status icon
2024-02-22 14:27:04 +01:00
project_status_rect = memnew ( TextureRect ) ;
project_status_rect - > set_stretch_mode ( TextureRect : : STRETCH_KEEP_CENTERED ) ;
pphb - > add_child ( project_status_rect ) ;
2024-01-16 19:50:38 +01:00
2024-02-22 14:27:04 +01:00
project_browse = memnew ( Button ) ;
project_browse - > set_text ( TTR ( " Browse " ) ) ;
2024-05-14 09:40:21 +02:00
project_browse - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ProjectDialog : : _browse_project_path ) ) ;
2024-02-22 14:27:04 +01:00
pphb - > add_child ( project_browse ) ;
2024-01-16 19:50:38 +01:00
// 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 " ) ) ;
2024-05-14 09:40:21 +02:00
install_browse - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ProjectDialog : : _browse_install_path ) ) ;
2024-01-16 19:50:38 +01:00
iphb - > add_child ( install_browse ) ;
msg = memnew ( Label ) ;
msg - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
msg - > set_custom_minimum_size ( Size2 ( 200 , 0 ) * EDSCALE ) ;
2024-02-22 14:27:04 +01:00
msg - > set_autowrap_mode ( TextServer : : AUTOWRAP_WORD_SMART ) ;
2024-01-16 19:50:38 +01:00
vb - > add_child ( msg ) ;
// Renderer selection.
renderer_container = memnew ( VBoxContainer ) ;
vb - > add_child ( renderer_container ) ;
l = memnew ( Label ) ;
l - > set_text ( TTR ( " Renderer: " ) ) ;
renderer_container - > add_child ( l ) ;
HBoxContainer * rshc = memnew ( HBoxContainer ) ;
renderer_container - > add_child ( rshc ) ;
renderer_button_group . instantiate ( ) ;
// Left hand side, used for checkboxes to select renderer.
Container * rvb = memnew ( VBoxContainer ) ;
rshc - > add_child ( rvb ) ;
String default_renderer_type = " forward_plus " ;
if ( EditorSettings : : get_singleton ( ) - > has_setting ( " project_manager/default_renderer " ) ) {
default_renderer_type = EditorSettings : : get_singleton ( ) - > get_setting ( " project_manager/default_renderer " ) ;
}
2024-04-25 19:37:38 +02:00
rendering_device_supported = DisplayServer : : can_create_rendering_device ( ) ;
if ( ! rendering_device_supported ) {
default_renderer_type = " gl_compatibility " ;
}
2024-01-16 19:50:38 +01:00
Button * rs_button = memnew ( CheckBox ) ;
rs_button - > set_button_group ( renderer_button_group ) ;
rs_button - > set_text ( TTR ( " Forward+ " ) ) ;
2024-04-25 19:37:38 +02:00
# ifndef RD_ENABLED
2024-01-16 19:50:38 +01:00
rs_button - > set_disabled ( true ) ;
# endif
rs_button - > set_meta ( SNAME ( " rendering_method " ) , " forward_plus " ) ;
2024-05-14 09:40:21 +02:00
rs_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ProjectDialog : : _renderer_selected ) ) ;
2024-01-16 19:50:38 +01:00
rvb - > add_child ( rs_button ) ;
if ( default_renderer_type = = " forward_plus " ) {
rs_button - > set_pressed ( true ) ;
}
rs_button = memnew ( CheckBox ) ;
rs_button - > set_button_group ( renderer_button_group ) ;
rs_button - > set_text ( TTR ( " Mobile " ) ) ;
2024-04-25 19:37:38 +02:00
# ifndef RD_ENABLED
2024-01-16 19:50:38 +01:00
rs_button - > set_disabled ( true ) ;
# endif
rs_button - > set_meta ( SNAME ( " rendering_method " ) , " mobile " ) ;
2024-05-14 09:40:21 +02:00
rs_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ProjectDialog : : _renderer_selected ) ) ;
2024-01-16 19:50:38 +01:00
rvb - > add_child ( rs_button ) ;
if ( default_renderer_type = = " mobile " ) {
rs_button - > set_pressed ( true ) ;
}
rs_button = memnew ( CheckBox ) ;
rs_button - > set_button_group ( renderer_button_group ) ;
rs_button - > set_text ( TTR ( " Compatibility " ) ) ;
# if !defined(GLES3_ENABLED)
rs_button - > set_disabled ( true ) ;
# endif
rs_button - > set_meta ( SNAME ( " rendering_method " ) , " gl_compatibility " ) ;
2024-05-14 09:40:21 +02:00
rs_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ProjectDialog : : _renderer_selected ) ) ;
2024-01-16 19:50:38 +01:00
rvb - > add_child ( rs_button ) ;
# if defined(GLES3_ENABLED)
if ( default_renderer_type = = " gl_compatibility " ) {
rs_button - > set_pressed ( true ) ;
}
# endif
rshc - > add_child ( memnew ( VSeparator ) ) ;
// Right hand side, used for text explaining each choice.
rvb = memnew ( VBoxContainer ) ;
rvb - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
rshc - > add_child ( rvb ) ;
renderer_info = memnew ( Label ) ;
renderer_info - > set_modulate ( Color ( 1 , 1 , 1 , 0.7 ) ) ;
rvb - > add_child ( renderer_info ) ;
2024-04-25 19:37:38 +02:00
rd_not_supported = memnew ( Label ) ;
rd_not_supported - > set_text ( TTR ( " Rendering Device backend not available. Please use the Compatibility renderer. " ) ) ;
rd_not_supported - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
rd_not_supported - > set_custom_minimum_size ( Size2 ( 200 , 0 ) * EDSCALE ) ;
rd_not_supported - > set_autowrap_mode ( TextServer : : AUTOWRAP_WORD_SMART ) ;
rd_not_supported - > set_visible ( false ) ;
renderer_container - > add_child ( rd_not_supported ) ;
2024-01-16 19:50:38 +01:00
_renderer_selected ( ) ;
l = memnew ( Label ) ;
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_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
l - > set_vertical_alignment ( VERTICAL_ALIGNMENT_CENTER ) ;
l - > set_modulate ( Color ( 1 , 1 , 1 , 0.7 ) ) ;
renderer_container - > add_child ( l ) ;
default_files_container = memnew ( HBoxContainer ) ;
vb - > add_child ( default_files_container ) ;
l = memnew ( Label ) ;
l - > set_text ( TTR ( " Version Control Metadata: " ) ) ;
default_files_container - > add_child ( l ) ;
vcs_metadata_selection = memnew ( OptionButton ) ;
vcs_metadata_selection - > set_custom_minimum_size ( Size2 ( 100 , 20 ) ) ;
vcs_metadata_selection - > add_item ( TTR ( " None " ) , ( int ) EditorVCSInterface : : VCSMetadata : : NONE ) ;
vcs_metadata_selection - > add_item ( TTR ( " Git " ) , ( int ) EditorVCSInterface : : VCSMetadata : : GIT ) ;
vcs_metadata_selection - > select ( ( int ) EditorVCSInterface : : VCSMetadata : : GIT ) ;
default_files_container - > add_child ( vcs_metadata_selection ) ;
Control * spacer = memnew ( Control ) ;
spacer - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
default_files_container - > add_child ( spacer ) ;
fdialog_install = memnew ( EditorFileDialog ) ;
fdialog_install - > set_previews_enabled ( false ) ; //Crucial, otherwise the engine crashes.
fdialog_install - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
add_child ( fdialog_install ) ;
2024-05-14 11:42:00 +02:00
project_name - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ProjectDialog : : _project_name_changed ) . unbind ( 1 ) ) ;
project_path - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ProjectDialog : : _project_path_changed ) . unbind ( 1 ) ) ;
install_path - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ProjectDialog : : _install_path_changed ) . unbind ( 1 ) ) ;
2024-01-16 19:50:38 +01:00
fdialog_install - > connect ( " dir_selected " , callable_mp ( this , & ProjectDialog : : _install_path_selected ) ) ;
fdialog_install - > connect ( " file_selected " , callable_mp ( this , & ProjectDialog : : _install_path_selected ) ) ;
set_hide_on_ok ( false ) ;
dialog_error = memnew ( AcceptDialog ) ;
add_child ( dialog_error ) ;
}