2014-02-10 01:10:30 +00:00
/*************************************************************************/
/* project_manager.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 12:16:55 +00:00
/* https://godotengine.org */
2014-02-10 01:10:30 +00:00
/*************************************************************************/
2019-01-01 11:53:14 +00:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 01:10:30 +00:00
/* */
/* 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. */
/*************************************************************************/
2018-01-04 23:50:27 +00:00
2014-02-10 01:10:30 +00:00
# include "project_manager.h"
2017-01-16 07:04:19 +00:00
2018-09-11 16:13:45 +00:00
# include "core/io/config_file.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/translation.h"
# include "core/version.h"
# include "core/version_hash.gen.h"
2017-03-05 15:44:50 +00:00
# include "editor_scale.h"
# include "editor_settings.h"
# include "editor_themes.h"
# include "scene/gui/center_container.h"
2014-02-10 01:10:30 +00:00
# include "scene/gui/line_edit.h"
2017-03-05 15:44:50 +00:00
# include "scene/gui/margin_container.h"
2014-02-10 01:10:30 +00:00
# include "scene/gui/panel_container.h"
2017-03-05 15:44:50 +00:00
# include "scene/gui/separator.h"
2017-01-14 09:52:54 +00:00
# include "scene/gui/texture_rect.h"
2017-03-05 15:44:50 +00:00
# include "scene/gui/tool_button.h"
2016-07-12 00:34:02 +00:00
2017-08-31 01:08:17 +00:00
class ProjectDialog : public ConfirmationDialog {
2014-02-10 01:10:30 +00:00
2017-08-31 01:08:17 +00:00
GDCLASS ( ProjectDialog , ConfirmationDialog ) ;
2014-02-10 01:10:30 +00:00
2016-07-12 00:34:02 +00:00
public :
enum Mode {
MODE_NEW ,
MODE_IMPORT ,
2017-09-07 00:04:41 +00:00
MODE_INSTALL ,
MODE_RENAME
2016-07-12 00:34:02 +00:00
} ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
private :
2017-08-31 01:08:17 +00:00
enum MessageType {
MESSAGE_ERROR ,
MESSAGE_WARNING ,
MESSAGE_SUCCESS
} ;
2018-06-21 04:17:52 +00:00
enum InputType {
PROJECT_PATH ,
INSTALL_PATH
} ;
2016-07-12 00:34:02 +00:00
Mode mode ;
2017-09-07 00:04:41 +00:00
Button * browse ;
2018-06-21 04:17:52 +00:00
Button * install_browse ;
2017-08-31 01:08:17 +00:00
Button * create_dir ;
Container * name_container ;
Container * path_container ;
2018-06-21 04:17:52 +00:00
Container * install_path_container ;
2019-01-21 23:59:53 +00:00
Container * rasterizer_container ;
Ref < ButtonGroup > rasterizer_button_group ;
2017-08-31 01:08:17 +00:00
Label * msg ;
2014-02-10 01:10:30 +00:00
LineEdit * project_path ;
LineEdit * project_name ;
2018-06-21 04:17:52 +00:00
LineEdit * install_path ;
2018-01-17 07:45:09 +00:00
TextureRect * status_rect ;
2018-06-21 04:17:52 +00:00
TextureRect * install_status_rect ;
2014-02-10 01:10:30 +00:00
FileDialog * fdialog ;
2018-06-21 04:17:52 +00:00
FileDialog * fdialog_install ;
2016-07-12 00:34:02 +00:00
String zip_path ;
String zip_title ;
AcceptDialog * dialog_error ;
2017-08-31 01:08:17 +00:00
String fav_dir ;
String created_folder_path ;
2018-06-21 04:17:52 +00:00
void set_message ( const String & p_msg , MessageType p_type = MESSAGE_SUCCESS , InputType input_type = PROJECT_PATH ) {
2017-12-26 23:39:46 +00:00
2017-08-31 01:08:17 +00:00
msg - > set_text ( p_msg ) ;
2018-06-21 04:17:52 +00:00
Ref < Texture > current_path_icon = status_rect - > get_texture ( ) ;
Ref < Texture > current_install_icon = install_status_rect - > get_texture ( ) ;
2018-01-17 07:45:09 +00:00
Ref < Texture > new_icon ;
2017-12-26 23:39:46 +00:00
2017-08-31 01:08:17 +00:00
switch ( p_type ) {
2017-12-26 23:39:46 +00:00
case MESSAGE_ERROR : {
2017-08-31 01:08:17 +00:00
msg - > add_color_override ( " font_color " , get_color ( " error_color " , " Editor " ) ) ;
2018-01-17 07:45:09 +00:00
msg - > set_modulate ( Color ( 1 , 1 , 1 , 1 ) ) ;
new_icon = get_icon ( " StatusError " , " EditorIcons " ) ;
2017-12-26 23:39:46 +00:00
} break ;
case MESSAGE_WARNING : {
2017-08-31 01:08:17 +00:00
msg - > add_color_override ( " font_color " , get_color ( " warning_color " , " Editor " ) ) ;
2018-01-17 07:45:09 +00:00
msg - > set_modulate ( Color ( 1 , 1 , 1 , 1 ) ) ;
new_icon = get_icon ( " StatusWarning " , " EditorIcons " ) ;
2017-12-26 23:39:46 +00:00
} break ;
case MESSAGE_SUCCESS : {
2018-01-17 07:45:09 +00:00
msg - > set_modulate ( Color ( 1 , 1 , 1 , 0 ) ) ;
new_icon = get_icon ( " StatusSuccess " , " EditorIcons " ) ;
2017-12-26 23:39:46 +00:00
} break ;
2017-08-31 01:08:17 +00:00
}
2017-12-26 23:39:46 +00:00
2018-06-21 04:17:52 +00:00
if ( current_path_icon ! = new_icon & & input_type = = PROJECT_PATH ) {
2018-01-17 07:45:09 +00:00
status_rect - > set_texture ( new_icon ) ;
2018-06-21 04:17:52 +00:00
} else if ( current_install_icon ! = new_icon & & input_type = = INSTALL_PATH ) {
install_status_rect - > set_texture ( new_icon ) ;
}
2018-01-17 07:45:09 +00:00
2017-12-26 23:39:46 +00:00
set_size ( Size2 ( 500 , 0 ) * EDSCALE ) ;
2017-08-31 01:08:17 +00:00
}
2014-02-10 01:10:30 +00:00
2016-11-14 12:40:05 +00:00
String _test_path ( ) {
2014-02-10 01:10:30 +00:00
DirAccess * d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2018-06-21 04:17:52 +00:00
String valid_path , valid_install_path ;
2017-03-05 15:44:50 +00:00
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 ( ) ;
2018-06-21 04:17:52 +00:00
} 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 ( ) ;
}
2016-11-14 12:40:05 +00:00
}
if ( valid_path = = " " ) {
2017-10-29 17:48:42 +00:00
set_message ( TTR ( " The path does not exist. " ) , MESSAGE_ERROR ) ;
2014-02-10 01:10:30 +00:00
memdelete ( d ) ;
2017-12-26 23:39:46 +00:00
get_ok ( ) - > set_disabled ( true ) ;
2016-11-14 12:40:05 +00:00
return " " ;
2014-02-10 01:10:30 +00:00
}
2018-06-21 04:17:52 +00:00
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 " " ;
}
}
2017-09-07 00:04:41 +00:00
if ( mode = = MODE_IMPORT | | mode = = MODE_RENAME ) {
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
if ( valid_path ! = " " & & ! d - > file_exists ( " project.godot " ) ) {
2014-02-10 01:10:30 +00:00
2018-06-21 04:17:52 +00:00
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 ) ;
2014-02-10 01:10:30 +00:00
memdelete ( d ) ;
2017-12-26 23:39:46 +00:00
get_ok ( ) - > set_disabled ( true ) ;
2016-11-14 12:40:05 +00:00
return " " ;
2014-02-10 01:10:30 +00:00
}
2018-01-28 13:36:24 +00:00
} else {
2017-08-31 01:08:17 +00:00
// check if the specified 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 ( ) ) {
2018-06-21 04:17:52 +00:00
if ( n ! = " . " & & n ! = " .. " ) { // i don't know if this is enough to guarantee an empty dir
2017-08-31 01:08:17 +00:00
is_empty = false ;
break ;
}
n = d - > get_next ( ) ;
}
d - > list_dir_end ( ) ;
if ( ! is_empty ) {
2017-12-26 23:39:46 +00:00
2018-01-18 10:24:20 +00:00
set_message ( TTR ( " Please choose an empty folder. " ) , MESSAGE_ERROR ) ;
2017-12-26 23:39:46 +00:00
memdelete ( d ) ;
2018-01-18 10:24:20 +00:00
get_ok ( ) - > set_disabled ( true ) ;
return " " ;
2017-08-31 01:08:17 +00:00
}
2014-02-10 01:10:30 +00:00
}
2018-01-17 07:45:09 +00:00
set_message ( " " ) ;
2018-06-21 04:17:52 +00:00
set_message ( " " , MESSAGE_SUCCESS , INSTALL_PATH ) ;
2014-02-10 01:10:30 +00:00
memdelete ( d ) ;
get_ok ( ) - > set_disabled ( false ) ;
2016-11-14 12:40:05 +00:00
return valid_path ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void _path_text_changed ( const String & p_path ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
String sp = _test_path ( ) ;
if ( sp ! = " " ) {
2014-02-10 01:10:30 +00:00
2019-06-14 21:53:40 +00:00
// 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 " ) ) {
2017-08-31 01:08:17 +00:00
sp = sp . replace ( " \\ " , " / " ) ;
int lidx = sp . find_last ( " / " ) ;
2014-02-10 01:10:30 +00:00
2017-08-31 01:08:17 +00:00
if ( lidx ! = - 1 ) {
2019-06-14 21:53:40 +00:00
sp = sp . substr ( lidx + 1 , sp . length ( ) ) . capitalize ( ) ;
2017-08-31 01:08:17 +00:00
}
if ( sp = = " " & & mode = = MODE_IMPORT )
sp = TTR ( " Imported Project " ) ;
project_name - > set_text ( sp ) ;
2018-05-19 22:59:11 +00:00
_text_changed ( sp ) ;
2014-02-10 01:10:30 +00:00
}
2017-08-31 01:08:17 +00:00
}
2014-02-10 01:10:30 +00:00
2017-08-31 01:08:17 +00:00
if ( created_folder_path ! = " " & & created_folder_path ! = p_path ) {
_remove_created_folder ( ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void _file_selected ( const String & p_path ) {
2014-02-10 01:10:30 +00:00
String p = p_path ;
2017-03-05 15:44:50 +00:00
if ( mode = = MODE_IMPORT ) {
2017-05-01 15:44:52 +00:00
if ( p . ends_with ( " project.godot " ) ) {
2017-03-05 15:44:50 +00:00
p = p . get_base_dir ( ) ;
2018-06-21 04:17:52 +00:00
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 ( ) ;
2017-08-31 01:08:17 +00:00
get_ok ( ) - > set_disabled ( false ) ;
} else {
2018-06-21 04:17:52 +00:00
set_message ( TTR ( " Please choose a 'project.godot' or '.zip' file. " ) , MESSAGE_ERROR ) ;
2017-08-31 01:08:17 +00:00
get_ok ( ) - > set_disabled ( true ) ;
return ;
2014-02-10 01:10:30 +00:00
}
}
String sp = p . simplify_path ( ) ;
project_path - > set_text ( sp ) ;
2018-05-19 22:59:11 +00:00
_path_text_changed ( sp ) ;
2018-06-21 04:17:52 +00:00
if ( p . ends_with ( " .zip " ) ) {
install_path - > call_deferred ( " grab_focus " ) ;
} else {
get_ok ( ) - > call_deferred ( " grab_focus " ) ;
}
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void _path_selected ( const String & p_path ) {
2014-02-10 01:10:30 +00:00
String p = p_path ;
String sp = p . simplify_path ( ) ;
project_path - > set_text ( sp ) ;
2018-05-19 22:59:11 +00:00
_path_text_changed ( sp ) ;
2016-10-06 10:41:38 +00:00
get_ok ( ) - > call_deferred ( " grab_focus " ) ;
2014-02-10 01:10:30 +00:00
}
2018-06-21 04:17:52 +00:00
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 " ) ;
}
2014-02-10 01:10:30 +00:00
void _browse_path ( ) {
2017-08-31 01:08:17 +00:00
fdialog - > set_current_dir ( project_path - > get_text ( ) ) ;
2017-03-05 15:44:50 +00:00
if ( mode = = MODE_IMPORT ) {
2014-02-10 01:10:30 +00:00
fdialog - > set_mode ( FileDialog : : MODE_OPEN_FILE ) ;
fdialog - > clear_filters ( ) ;
2017-11-19 20:18:01 +00:00
fdialog - > add_filter ( " project.godot ; " VERSION_NAME " Project " ) ;
2018-06-21 04:17:52 +00:00
fdialog - > add_filter ( " *.zip ; Zip File " ) ;
2014-02-10 01:10:30 +00:00
} else {
fdialog - > set_mode ( FileDialog : : MODE_OPEN_DIR ) ;
}
fdialog - > popup_centered_ratio ( ) ;
}
2018-06-21 04:17:52 +00:00
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 ( ) ;
}
2017-08-31 01:08:17 +00:00
void _create_folder ( ) {
2017-09-07 00:04:41 +00:00
2018-05-01 19:07:41 +00:00
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 ) ;
2017-09-07 00:04:41 +00:00
return ;
2018-05-01 19:07:41 +00:00
}
2017-08-31 01:08:17 +00:00
DirAccess * d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
if ( d - > change_dir ( project_path - > get_text ( ) ) = = OK ) {
2017-12-26 23:39:46 +00:00
2017-08-31 01:08:17 +00:00
if ( ! d - > dir_exists ( project_name - > get_text ( ) ) ) {
2017-12-26 23:39:46 +00:00
2017-08-31 01:08:17 +00:00
if ( d - > make_dir ( project_name - > get_text ( ) ) = = OK ) {
2017-12-26 23:39:46 +00:00
2017-08-31 01:08:17 +00:00
d - > change_dir ( project_name - > get_text ( ) ) ;
2018-05-19 22:59:11 +00:00
String dir_str = d - > get_current_dir ( ) ;
project_path - > set_text ( dir_str ) ;
_path_text_changed ( dir_str ) ;
2017-08-31 01:08:17 +00:00
created_folder_path = d - > get_current_dir ( ) ;
create_dir - > set_disabled ( true ) ;
2017-12-26 23:39:46 +00:00
} else {
dialog_error - > set_text ( TTR ( " Couldn't create folder. " ) ) ;
dialog_error - > popup_centered_minsize ( ) ;
2017-08-31 01:08:17 +00:00
}
2017-12-26 23:39:46 +00:00
} else {
dialog_error - > set_text ( TTR ( " There is already a folder in this path with the specified name. " ) ) ;
dialog_error - > popup_centered_minsize ( ) ;
2017-08-31 01:08:17 +00:00
}
}
2017-12-26 23:39:46 +00:00
2017-08-31 01:08:17 +00:00
memdelete ( d ) ;
2017-09-07 00:04:41 +00:00
}
2017-08-31 01:08:17 +00:00
void _text_changed ( const String & p_text ) {
if ( mode ! = MODE_NEW )
return ;
_test_path ( ) ;
if ( p_text = = " " )
set_message ( TTR ( " It would be a good idea to name your project. " ) , MESSAGE_WARNING ) ;
2014-02-10 01:10:30 +00:00
}
void ok_pressed ( ) {
2017-08-31 01:08:17 +00:00
String dir = project_path - > get_text ( ) ;
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
if ( mode = = MODE_RENAME ) {
2019-02-12 20:10:08 +00:00
String dir2 = _test_path ( ) ;
if ( dir2 = = " " ) {
2017-08-31 01:08:17 +00:00
set_message ( TTR ( " Invalid project path (changed anything?). " ) , MESSAGE_ERROR ) ;
2017-09-07 00:04:41 +00:00
return ;
}
ProjectSettings * current = memnew ( ProjectSettings ) ;
2019-02-12 20:10:08 +00:00
int err = current - > setup ( dir2 , " " ) ;
2018-02-19 13:53:59 +00:00
if ( err ! = OK ) {
set_message ( vformat ( TTR ( " Couldn't load project.godot in project path (error %d). It may be missing or corrupted. " ) , err ) , MESSAGE_ERROR ) ;
2017-09-07 00:04:41 +00:00
} else {
ProjectSettings : : CustomMap edited_settings ;
edited_settings [ " application/config/name " ] = project_name - > get_text ( ) ;
2019-02-12 20:10:08 +00:00
if ( current - > save_custom ( dir2 . plus_file ( " project.godot " ) , edited_settings , Vector < String > ( ) , true ) ! = OK ) {
2017-08-31 01:08:17 +00:00
set_message ( TTR ( " Couldn't edit project.godot in project path. " ) , MESSAGE_ERROR ) ;
2017-09-07 00:04:41 +00:00
}
}
hide ( ) ;
2018-12-21 11:20:48 +00:00
emit_signal ( " projects_updated " ) ;
2014-02-10 01:10:30 +00:00
} else {
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
if ( mode = = MODE_IMPORT ) {
2018-06-21 04:17:52 +00:00
if ( project_path - > get_text ( ) . ends_with ( " .zip " ) ) {
mode = MODE_INSTALL ;
ok_pressed ( ) ;
return ;
}
2017-09-07 00:04:41 +00:00
} else {
if ( mode = = MODE_NEW ) {
2017-07-26 13:28:54 +00:00
2017-09-07 00:04:41 +00:00
ProjectSettings : : CustomMap initial_settings ;
2019-01-21 23:59:53 +00:00
if ( rasterizer_button_group - > get_pressed_button ( ) - > get_meta ( " driver_name " ) = = " GLES3 " ) {
initial_settings [ " rendering/quality/driver/driver_name " ] = " GLES3 " ;
} else {
initial_settings [ " rendering/quality/driver/driver_name " ] = " GLES2 " ;
initial_settings [ " rendering/vram_compression/import_etc2 " ] = false ;
initial_settings [ " rendering/vram_compression/import_etc " ] = true ;
}
2017-09-07 00:04:41 +00:00
initial_settings [ " application/config/name " ] = project_name - > get_text ( ) ;
initial_settings [ " application/config/icon " ] = " res://icon.png " ;
initial_settings [ " rendering/environment/default_environment " ] = " res://default_env.tres " ;
2017-05-29 00:46:48 +00:00
2018-12-21 11:20:48 +00:00
if ( ProjectSettings : : get_singleton ( ) - > save_custom ( dir . plus_file ( " project.godot " ) , initial_settings , Vector < String > ( ) , false ) ! = OK ) {
2017-08-31 01:08:17 +00:00
set_message ( TTR ( " Couldn't create project.godot in project path. " ) , MESSAGE_ERROR ) ;
2017-05-29 00:46:48 +00:00
} else {
2018-12-21 11:20:48 +00:00
ResourceSaver : : save ( dir . plus_file ( " icon.png " ) , get_icon ( " DefaultProjectIcon " , " EditorIcons " ) ) ;
2017-09-07 00:04:41 +00:00
2018-12-21 11:20:48 +00:00
FileAccess * f = FileAccess : : open ( dir . plus_file ( " default_env.tres " ) , FileAccess : : WRITE ) ;
2017-09-07 00:04:41 +00:00
if ( ! f ) {
2017-08-31 01:08:17 +00:00
set_message ( TTR ( " Couldn't create project.godot in project path. " ) , MESSAGE_ERROR ) ;
2017-09-07 00:04:41 +00:00
} else {
f - > store_line ( " [gd_resource type= \" Environment \" load_steps=2 format=2] " ) ;
f - > store_line ( " [sub_resource type= \" ProceduralSky \" id=1] " ) ;
f - > store_line ( " [resource] " ) ;
f - > store_line ( " background_mode = 2 " ) ;
f - > store_line ( " background_sky = SubResource( 1 ) " ) ;
memdelete ( f ) ;
}
2017-05-29 00:46:48 +00:00
}
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
} else if ( mode = = MODE_INSTALL ) {
2016-07-12 00:34:02 +00:00
2018-06-21 04:17:52 +00:00
if ( project_path - > get_text ( ) . ends_with ( " .zip " ) ) {
dir = install_path - > get_text ( ) ;
zip_path = project_path - > get_text ( ) ;
}
2017-09-07 00:04:41 +00:00
FileAccess * src_f = NULL ;
zlib_filefunc_def io = zipio_create_io_from_file ( & src_f ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
unzFile pkg = unzOpen2 ( zip_path . utf8 ( ) . get_data ( ) , & io ) ;
if ( ! pkg ) {
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
dialog_error - > set_text ( TTR ( " Error opening package file, not in zip format. " ) ) ;
2017-12-26 23:39:46 +00:00
dialog_error - > popup_centered_minsize ( ) ;
2017-09-07 00:04:41 +00:00
return ;
}
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
int ret = unzGoToFirstFile ( pkg ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
Vector < String > failed_files ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
int idx = 0 ;
while ( ret = = UNZ_OK ) {
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
//get filename
unz_file_info info ;
char fname [ 16384 ] ;
ret = unzGetCurrentFileInfo ( pkg , & info , fname , 16384 , NULL , 0 , NULL , 0 ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
String path = fname ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
int depth = 1 ; //stuff from github comes with tag
bool skip = false ;
while ( depth > 0 ) {
int pp = path . find ( " / " ) ;
if ( pp = = - 1 ) {
skip = true ;
break ;
}
path = path . substr ( pp + 1 , path . length ( ) ) ;
depth - - ;
2016-07-12 00:34:02 +00:00
}
2017-09-07 00:04:41 +00:00
if ( skip | | path = = String ( ) ) {
//
} else if ( path . ends_with ( " / " ) ) { // a dir
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
path = path . substr ( 0 , path . length ( ) - 1 ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
da - > make_dir ( dir . plus_file ( path ) ) ;
memdelete ( da ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
} else {
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
Vector < uint8_t > data ;
data . resize ( info . uncompressed_size ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
//read
unzOpenCurrentFile ( pkg ) ;
2017-11-25 03:07:54 +00:00
unzReadCurrentFile ( pkg , data . ptrw ( ) , data . size ( ) ) ;
2017-09-07 00:04:41 +00:00
unzCloseCurrentFile ( pkg ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
FileAccess * f = FileAccess : : open ( dir . plus_file ( path ) , FileAccess : : WRITE ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
if ( f ) {
f - > store_buffer ( data . ptr ( ) , data . size ( ) ) ;
memdelete ( f ) ;
} else {
failed_files . push_back ( path ) ;
}
2016-07-12 00:34:02 +00:00
}
2017-09-07 00:04:41 +00:00
idx + + ;
ret = unzGoToNextFile ( pkg ) ;
}
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
unzClose ( pkg ) ;
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
if ( failed_files . size ( ) ) {
String msg = TTR ( " The following files failed extraction from package: " ) + " \n \n " ;
for ( int i = 0 ; i < failed_files . size ( ) ; i + + ) {
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
if ( i > 15 ) {
msg + = " \n And " + itos ( failed_files . size ( ) - i ) + " more files. " ;
break ;
}
msg + = failed_files [ i ] + " \n " ;
2016-07-12 00:34:02 +00:00
}
2017-09-07 00:04:41 +00:00
dialog_error - > set_text ( msg ) ;
dialog_error - > popup_centered_minsize ( ) ;
2016-07-12 00:34:02 +00:00
2018-06-21 04:17:52 +00:00
} else if ( ! project_path - > get_text ( ) . ends_with ( " .zip " ) ) {
2018-12-21 11:20:48 +00:00
dialog_error - > set_text ( TTR ( " Package installed successfully! " ) ) ;
2017-09-07 00:04:41 +00:00
dialog_error - > popup_centered_minsize ( ) ;
}
2016-07-12 00:34:02 +00:00
}
2014-02-10 01:10:30 +00:00
}
2017-09-07 00:04:41 +00:00
dir = dir . replace ( " \\ " , " / " ) ;
if ( dir . ends_with ( " / " ) )
dir = dir . substr ( 0 , dir . length ( ) - 1 ) ;
String proj = dir . replace ( " / " , " :: " ) ;
EditorSettings : : get_singleton ( ) - > set ( " projects/ " + proj , dir ) ;
EditorSettings : : get_singleton ( ) - > save ( ) ;
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
hide ( ) ;
emit_signal ( " project_created " , dir ) ;
}
2014-02-10 01:10:30 +00:00
}
2017-08-31 01:08:17 +00:00
void _remove_created_folder ( ) {
if ( created_folder_path ! = " " ) {
DirAccess * d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
d - > remove ( created_folder_path ) ;
memdelete ( d ) ;
create_dir - > set_disabled ( false ) ;
created_folder_path = " " ;
}
}
void cancel_pressed ( ) {
_remove_created_folder ( ) ;
project_path - > clear ( ) ;
2018-05-19 22:59:11 +00:00
_path_text_changed ( " " ) ;
2017-08-31 01:08:17 +00:00
project_name - > clear ( ) ;
2018-05-19 22:59:11 +00:00
_text_changed ( " " ) ;
2017-12-26 23:39:46 +00:00
2018-01-17 07:45:09 +00:00
if ( status_rect - > get_texture ( ) = = get_icon ( " StatusError " , " EditorIcons " ) )
2017-12-26 23:39:46 +00:00
msg - > show ( ) ;
2018-06-21 04:17:52 +00:00
if ( install_status_rect - > get_texture ( ) = = get_icon ( " StatusError " , " EditorIcons " ) )
msg - > show ( ) ;
2017-12-26 23:39:46 +00:00
}
void _notification ( int p_what ) {
if ( p_what = = MainLoop : : NOTIFICATION_WM_QUIT_REQUEST )
_remove_created_folder ( ) ;
2017-08-31 01:08:17 +00:00
}
2014-02-10 01:10:30 +00:00
protected :
static void _bind_methods ( ) {
2017-08-31 01:08:17 +00:00
ClassDB : : bind_method ( " _browse_path " , & ProjectDialog : : _browse_path ) ;
ClassDB : : bind_method ( " _create_folder " , & ProjectDialog : : _create_folder ) ;
ClassDB : : bind_method ( " _text_changed " , & ProjectDialog : : _text_changed ) ;
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 ) ;
2018-06-21 04:17:52 +00:00
ClassDB : : bind_method ( " _install_path_selected " , & ProjectDialog : : _install_path_selected ) ;
ClassDB : : bind_method ( " _browse_install_path " , & ProjectDialog : : _browse_install_path ) ;
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " project_created " ) ) ;
2018-12-21 11:20:48 +00:00
ADD_SIGNAL ( MethodInfo ( " projects_updated " ) ) ;
2014-02-10 01:10:30 +00:00
}
public :
2017-03-05 15:44:50 +00:00
void set_zip_path ( const String & p_path ) {
zip_path = p_path ;
2016-07-12 00:34:02 +00:00
}
2017-03-05 15:44:50 +00:00
void set_zip_title ( const String & p_title ) {
zip_title = p_title ;
2016-07-12 00:34:02 +00:00
}
2014-02-10 01:10:30 +00:00
2016-07-12 00:34:02 +00:00
void set_mode ( Mode p_mode ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
mode = p_mode ;
2014-02-10 01:10:30 +00:00
}
2017-09-07 00:04:41 +00:00
void set_project_path ( const String & p_path ) {
project_path - > set_text ( p_path ) ;
}
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
void show_dialog ( ) {
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
if ( mode = = MODE_RENAME ) {
2016-07-12 00:34:02 +00:00
2017-09-07 00:04:41 +00:00
project_path - > set_editable ( false ) ;
2017-08-31 01:08:17 +00:00
browse - > hide ( ) ;
2018-06-21 04:17:52 +00:00
install_browse - > hide ( ) ;
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
set_title ( TTR ( " Rename Project " ) ) ;
get_ok ( ) - > set_text ( TTR ( " Rename " ) ) ;
2017-08-31 01:08:17 +00:00
name_container - > show ( ) ;
2018-01-28 13:36:24 +00:00
status_rect - > hide ( ) ;
msg - > hide ( ) ;
2018-06-21 04:17:52 +00:00
install_path_container - > hide ( ) ;
install_status_rect - > hide ( ) ;
2019-01-21 23:59:53 +00:00
rasterizer_container - > hide ( ) ;
2018-01-28 13:36:24 +00:00
get_ok ( ) - > set_disabled ( false ) ;
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
ProjectSettings * current = memnew ( ProjectSettings ) ;
2016-07-12 00:34:02 +00:00
2018-02-19 13:53:59 +00:00
int err = current - > setup ( project_path - > get_text ( ) , " " ) ;
if ( err ! = OK ) {
set_message ( vformat ( TTR ( " Couldn't load project.godot in project path (error %d). It may be missing or corrupted. " ) , err ) , MESSAGE_ERROR ) ;
2018-01-28 13:36:24 +00:00
status_rect - > show ( ) ;
msg - > show ( ) ;
get_ok ( ) - > set_disabled ( true ) ;
2017-10-05 18:34:34 +00:00
} else if ( current - > has_setting ( " application/config/name " ) ) {
2018-05-19 22:59:11 +00:00
String proj = current - > get ( " application/config/name " ) ;
project_name - > set_text ( proj ) ;
_text_changed ( proj ) ;
2017-09-07 00:04:41 +00:00
}
2017-12-06 18:54:22 +00:00
2017-12-06 03:24:01 +00:00
project_name - > call_deferred ( " grab_focus " ) ;
2014-02-10 01:10:30 +00:00
2017-08-31 01:08:17 +00:00
create_dir - > hide ( ) ;
2017-09-07 00:04:41 +00:00
} else {
2017-08-31 01:08:17 +00:00
fav_dir = EditorSettings : : get_singleton ( ) - > get ( " filesystem/directories/default_project_path " ) ;
if ( fav_dir ! = " " ) {
project_path - > set_text ( fav_dir ) ;
fdialog - > set_current_dir ( fav_dir ) ;
} else {
DirAccess * d = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
project_path - > set_text ( d - > get_current_dir ( ) ) ;
fdialog - > set_current_dir ( d - > get_current_dir ( ) ) ;
memdelete ( d ) ;
}
2018-05-19 22:59:11 +00:00
String proj = TTR ( " New Game Project " ) ;
project_name - > set_text ( proj ) ;
_text_changed ( proj ) ;
2017-08-31 01:08:17 +00:00
2017-09-07 00:04:41 +00:00
project_path - > set_editable ( true ) ;
browse - > set_disabled ( false ) ;
2017-08-31 01:08:17 +00:00
browse - > show ( ) ;
2018-06-21 04:17:52 +00:00
install_browse - > set_disabled ( false ) ;
install_browse - > show ( ) ;
2017-08-31 01:08:17 +00:00
create_dir - > show ( ) ;
2018-01-17 07:45:09 +00:00
status_rect - > show ( ) ;
2018-06-21 04:17:52 +00:00
install_status_rect - > show ( ) ;
2018-01-17 07:45:09 +00:00
msg - > show ( ) ;
2017-09-07 00:04:41 +00:00
if ( mode = = MODE_IMPORT ) {
set_title ( TTR ( " Import Existing Project " ) ) ;
2017-12-23 02:06:03 +00:00
get_ok ( ) - > set_text ( TTR ( " Import & Edit " ) ) ;
2017-08-31 01:08:17 +00:00
name_container - > hide ( ) ;
2018-06-21 04:17:52 +00:00
install_path_container - > hide ( ) ;
2019-01-21 23:59:53 +00:00
rasterizer_container - > hide ( ) ;
2017-08-31 01:08:17 +00:00
project_path - > grab_focus ( ) ;
2017-09-07 00:04:41 +00:00
} else if ( mode = = MODE_NEW ) {
set_title ( TTR ( " Create New Project " ) ) ;
2017-12-23 02:06:03 +00:00
get_ok ( ) - > set_text ( TTR ( " Create & Edit " ) ) ;
2017-08-31 01:08:17 +00:00
name_container - > show ( ) ;
2018-06-21 04:17:52 +00:00
install_path_container - > hide ( ) ;
2019-01-21 23:59:53 +00:00
rasterizer_container - > show ( ) ;
2018-11-26 07:56:34 +00:00
project_name - > call_deferred ( " grab_focus " ) ;
project_name - > call_deferred ( " select_all " ) ;
2017-09-07 00:04:41 +00:00
} else if ( mode = = MODE_INSTALL ) {
set_title ( TTR ( " Install Project: " ) + " " + zip_title ) ;
2017-12-23 02:06:03 +00:00
get_ok ( ) - > set_text ( TTR ( " Install & Edit " ) ) ;
2019-03-17 21:32:00 +00:00
name_container - > show ( ) ;
2018-06-21 04:17:52 +00:00
install_path_container - > hide ( ) ;
2019-01-21 23:59:53 +00:00
rasterizer_container - > hide ( ) ;
2017-08-31 01:08:17 +00:00
project_path - > grab_focus ( ) ;
2017-09-07 00:04:41 +00:00
}
_test_path ( ) ;
}
2017-08-31 01:08:17 +00:00
2019-01-21 23:59:53 +00:00
popup_centered_minsize ( Size2 ( 500 , 0 ) * EDSCALE ) ;
2014-02-10 01:10:30 +00:00
}
2017-08-31 01:08:17 +00:00
ProjectDialog ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
2014-02-10 01:10:30 +00:00
add_child ( vb ) ;
2017-08-31 01:08:17 +00:00
name_container = memnew ( VBoxContainer ) ;
vb - > add_child ( name_container ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Label * l = memnew ( Label ) ;
2017-08-31 01:08:17 +00:00
l - > set_text ( TTR ( " Project Name: " ) ) ;
name_container - > add_child ( l ) ;
HBoxContainer * pnhb = memnew ( HBoxContainer ) ;
name_container - > add_child ( pnhb ) ;
project_name = memnew ( LineEdit ) ;
project_name - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
pnhb - > add_child ( project_name ) ;
create_dir = memnew ( Button ) ;
pnhb - > add_child ( create_dir ) ;
2019-03-25 00:54:29 +00:00
create_dir - > set_text ( TTR ( " Create Folder " ) ) ;
2017-08-31 01:08:17 +00:00
create_dir - > connect ( " pressed " , this , " _create_folder " ) ;
path_container = memnew ( VBoxContainer ) ;
vb - > add_child ( path_container ) ;
l = memnew ( Label ) ;
2016-05-04 01:25:37 +00:00
l - > set_text ( TTR ( " Project Path: " ) ) ;
2017-08-31 01:08:17 +00:00
path_container - > add_child ( l ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
HBoxContainer * pphb = memnew ( HBoxContainer ) ;
2017-08-31 01:08:17 +00:00
path_container - > add_child ( pphb ) ;
project_path = memnew ( LineEdit ) ;
2014-02-10 01:10:30 +00:00
project_path - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2017-08-31 01:08:17 +00:00
pphb - > add_child ( project_path ) ;
2018-06-21 04:17:52 +00:00
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 ) ;
2018-01-28 13:36:24 +00:00
// status icon
2018-01-17 07:45:09 +00:00
status_rect = memnew ( TextureRect ) ;
status_rect - > set_stretch_mode ( TextureRect : : STRETCH_KEEP_CENTERED ) ;
pphb - > add_child ( status_rect ) ;
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
browse = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
browse - > set_text ( TTR ( " Browse " ) ) ;
2017-03-05 15:44:50 +00:00
browse - > connect ( " pressed " , this , " _browse_path " ) ;
2017-08-31 01:08:17 +00:00
pphb - > add_child ( browse ) ;
2014-02-10 01:10:30 +00:00
2018-06-21 04:17:52 +00: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 " ) ) ;
install_browse - > connect ( " pressed " , this , " _browse_install_path " ) ;
iphb - > add_child ( install_browse ) ;
2017-08-31 01:08:17 +00:00
msg = memnew ( Label ) ;
msg - > set_align ( Label : : ALIGN_CENTER ) ;
vb - > add_child ( msg ) ;
2014-02-10 01:10:30 +00:00
2019-01-21 23:59:53 +00:00
// rasterizer selection
rasterizer_container = memnew ( VBoxContainer ) ;
vb - > add_child ( rasterizer_container ) ;
l = memnew ( Label ) ;
l - > set_text ( TTR ( " Renderer: " ) ) ;
rasterizer_container - > add_child ( l ) ;
Container * rshb = memnew ( HBoxContainer ) ;
rasterizer_container - > add_child ( rshb ) ;
rasterizer_button_group . instance ( ) ;
Container * rvb = memnew ( VBoxContainer ) ;
rvb - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
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_pressed ( true ) ;
rvb - > add_child ( rs_button ) ;
l = memnew ( Label ) ;
l - > set_text ( TTR ( " Higher visual quality \n All features available \n Incompatible with older hardware \n Not recommended for web games " ) ) ;
rvb - > add_child ( l ) ;
rshb - > add_child ( memnew ( VSeparator ) ) ;
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_meta ( " driver_name " , " GLES2 " ) ;
rvb - > add_child ( rs_button ) ;
l = memnew ( Label ) ;
l - > set_text ( TTR ( " Lower visual quality \n Some features not available \n Works on most hardware \n Recommended for web games " ) ) ;
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_align ( Label : : ALIGN_CENTER ) ;
rasterizer_container - > add_child ( l ) ;
2017-03-05 15:44:50 +00:00
fdialog = memnew ( FileDialog ) ;
2014-02-10 01:10:30 +00:00
fdialog - > set_access ( FileDialog : : ACCESS_FILESYSTEM ) ;
2018-06-21 04:17:52 +00:00
fdialog_install = memnew ( FileDialog ) ;
fdialog_install - > set_access ( FileDialog : : ACCESS_FILESYSTEM ) ;
2017-08-31 01:08:17 +00:00
add_child ( fdialog ) ;
2018-06-21 04:17:52 +00:00
add_child ( fdialog_install ) ;
2017-03-05 15:44:50 +00:00
project_name - > connect ( " text_changed " , this , " _text_changed " ) ;
project_path - > connect ( " text_changed " , this , " _path_text_changed " ) ;
2018-06-21 04:17:52 +00:00
install_path - > connect ( " text_changed " , this , " _path_text_changed " ) ;
2017-03-05 15:44:50 +00:00
fdialog - > connect ( " dir_selected " , this , " _path_selected " ) ;
fdialog - > connect ( " file_selected " , this , " _file_selected " ) ;
2018-06-21 04:17:52 +00:00
fdialog_install - > connect ( " dir_selected " , this , " _install_path_selected " ) ;
fdialog_install - > connect ( " file_selected " , this , " _install_path_selected " ) ;
2018-12-21 11:20:48 +00:00
2014-02-10 01:10:30 +00:00
set_hide_on_ok ( false ) ;
2017-03-05 15:44:50 +00:00
mode = MODE_NEW ;
2016-07-12 00:34:02 +00:00
2017-03-05 15:44:50 +00:00
dialog_error = memnew ( AcceptDialog ) ;
2016-07-12 00:34:02 +00:00
add_child ( dialog_error ) ;
2014-02-10 01:10:30 +00:00
}
} ;
2014-05-01 11:30:10 +00:00
struct ProjectItem {
String project ;
String path ;
String conf ;
2018-12-21 11:20:48 +00:00
int config_version ;
2014-05-01 11:30:10 +00:00
uint64_t last_modified ;
2014-05-20 08:38:18 +00:00
bool favorite ;
2017-09-11 05:01:20 +00:00
bool grayed ;
2018-11-23 19:15:33 +00:00
bool ordered_latest_modification ;
2014-05-01 11:30:10 +00:00
ProjectItem ( ) { }
2018-12-21 11:20:48 +00:00
ProjectItem ( const String & p_project , const String & p_path , const String & p_conf , int p_config_version , uint64_t p_last_modified , bool p_favorite = false , bool p_grayed = false , const bool p_ordered_latest_modification = true ) {
2017-03-05 15:44:50 +00:00
project = p_project ;
path = p_path ;
conf = p_conf ;
2018-12-21 11:20:48 +00:00
config_version = p_config_version ;
2017-03-05 15:44:50 +00:00
last_modified = p_last_modified ;
favorite = p_favorite ;
2017-09-11 05:01:20 +00:00
grayed = p_grayed ;
2018-11-23 19:15:33 +00:00
ordered_latest_modification = p_ordered_latest_modification ;
}
_FORCE_INLINE_ bool operator < ( const ProjectItem & l ) const {
if ( ordered_latest_modification )
return last_modified > l . last_modified ;
return project < l . project ;
2014-05-01 11:30:10 +00:00
}
2017-03-05 15:44:50 +00:00
_FORCE_INLINE_ bool operator = = ( const ProjectItem & l ) const { return project = = l . project ; }
2014-05-01 11:30:10 +00:00
} ;
2014-02-10 01:10:30 +00:00
2015-12-14 19:31:37 +00:00
void ProjectManager : : _notification ( int p_what ) {
2017-12-26 23:39:46 +00:00
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
2017-11-26 18:31:08 +00:00
2017-12-26 23:39:46 +00:00
Engine : : get_singleton ( ) - > set_editor_hint ( false ) ;
} break ;
case NOTIFICATION_READY : {
2017-11-26 18:31:08 +00:00
2018-03-04 10:40:40 +00:00
if ( scroll_children - > get_child_count ( ) = = 0 & & StreamPeerSSL : : is_available ( ) )
2017-12-26 23:39:46 +00:00
open_templates - > popup_centered_minsize ( ) ;
} break ;
case NOTIFICATION_VISIBILITY_CHANGED : {
2016-07-23 19:37:25 +00:00
2017-12-26 23:39:46 +00:00
set_process_unhandled_input ( is_visible_in_tree ( ) ) ;
} break ;
2019-06-09 20:33:50 +00:00
case NOTIFICATION_WM_QUIT_REQUEST : {
_dim_window ( ) ;
} break ;
2015-12-14 19:31:37 +00:00
}
}
2014-05-11 01:45:52 +00:00
2019-06-09 20:33:50 +00:00
void ProjectManager : : _dim_window ( ) {
// This method must be called before calling `get_tree()->quit()`.
// Otherwise, its effect won't be visible
// Dim the project manager window while it's quitting to make it clearer that it's busy.
// No transition is applied, as the effect needs to be visible immediately
float c = 1.0f - float ( EDITOR_GET ( " interface/editor/dim_amount " ) ) ;
Color dim_color = Color ( c , c , c ) ;
gui_base - > set_modulate ( dim_color ) ;
}
2014-02-10 01:10:30 +00:00
void ProjectManager : : _panel_draw ( Node * p_hb ) {
2017-08-24 20:58:51 +00:00
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( p_hb ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
hb - > draw_line ( Point2 ( 0 , hb - > get_size ( ) . y + 1 ) , Point2 ( hb - > get_size ( ) . x - 10 , hb - > get_size ( ) . y + 1 ) , get_color ( " guide_color " , " Tree " ) ) ;
2014-02-10 01:10:30 +00:00
2014-05-01 13:47:45 +00:00
if ( selected_list . has ( hb - > get_meta ( " name " ) ) ) {
2017-08-31 01:08:17 +00:00
hb - > draw_style_box ( gui_base - > get_stylebox ( " selected " , " Tree " ) , Rect2 ( Point2 ( ) , hb - > get_size ( ) - Size2 ( 10 , 0 ) * EDSCALE ) ) ;
2014-02-10 01:10:30 +00:00
}
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _update_project_buttons ( ) {
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
2016-08-05 14:06:16 +00:00
2018-01-18 20:37:17 +00:00
CanvasItem * item = Object : : cast_to < CanvasItem > ( scroll_children - > get_child ( i ) ) ;
2016-07-29 00:33:59 +00:00
item - > update ( ) ;
2016-07-30 22:04:16 +00:00
}
2016-08-05 14:06:16 +00:00
2018-05-09 06:28:01 +00:00
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 ) ;
2019-02-11 16:44:23 +00:00
bool missing_projects = false ;
Map < String , String > list_all_projects ;
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
if ( hb ) {
list_all_projects . insert ( hb - > get_meta ( " name " ) , hb - > get_meta ( " main_scene " ) ) ;
}
}
for ( Map < String , String > : : Element * E = list_all_projects . front ( ) ; E ; E = E - > next ( ) ) {
2019-05-01 12:36:04 +00:00
String project_name = E - > key ( ) . replace ( " ::: " , " :/ " ) . replace ( " :: " , " / " ) + " /project.godot " ;
2019-02-11 16:44:23 +00:00
if ( ! FileAccess : : exists ( project_name ) ) {
missing_projects = true ;
break ;
}
}
erase_missing_btn - > set_visible ( missing_projects ) ;
2016-07-29 00:33:59 +00:00
}
2017-05-20 15:38:03 +00:00
void ProjectManager : : _panel_input ( const Ref < InputEvent > & p_ev , Node * p_hb ) {
2014-02-10 01:10:30 +00:00
2017-05-20 15:38:03 +00:00
Ref < InputEventMouseButton > mb = p_ev ;
if ( mb . is_valid ( ) & & mb - > is_pressed ( ) & & mb - > get_button_index ( ) = = BUTTON_LEFT ) {
2014-02-10 01:10:30 +00:00
2014-05-01 13:47:45 +00:00
String clicked = p_hb - > get_meta ( " name " ) ;
2014-05-11 01:45:52 +00:00
String clicked_main_scene = p_hb - > get_meta ( " main_scene " ) ;
2014-05-01 13:47:45 +00:00
2017-05-20 15:38:03 +00:00
if ( mb - > get_shift ( ) & & selected_list . size ( ) > 0 & & last_clicked ! = " " & & clicked ! = last_clicked ) {
2014-05-01 13:47:45 +00:00
int clicked_id = - 1 ;
int last_clicked_id = - 1 ;
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2014-05-01 13:47:45 +00:00
if ( ! hb ) continue ;
if ( hb - > get_meta ( " name " ) = = clicked ) clicked_id = i ;
if ( hb - > get_meta ( " name " ) = = last_clicked ) last_clicked_id = i ;
}
2017-03-05 15:44:50 +00:00
if ( last_clicked_id ! = - 1 & & clicked_id ! = - 1 ) {
int min = clicked_id < last_clicked_id ? clicked_id : last_clicked_id ;
int max = clicked_id > last_clicked_id ? clicked_id : last_clicked_id ;
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; + + i ) {
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2014-05-01 13:47:45 +00:00
if ( ! hb ) continue ;
2017-05-20 15:38:03 +00:00
if ( i ! = clicked_id & & ( i < min | | i > max ) & & ! mb - > get_control ( ) ) {
2014-05-01 13:47:45 +00:00
selected_list . erase ( hb - > get_meta ( " name " ) ) ;
2017-03-05 15:44:50 +00:00
} else if ( i > = min & & i < = max ) {
2014-05-11 01:45:52 +00:00
selected_list . insert ( hb - > get_meta ( " name " ) , hb - > get_meta ( " main_scene " ) ) ;
2014-05-01 13:47:45 +00:00
}
}
}
2017-05-20 15:38:03 +00:00
} else if ( selected_list . has ( clicked ) & & mb - > get_control ( ) ) {
2014-05-01 13:47:45 +00:00
selected_list . erase ( clicked ) ;
} else {
last_clicked = clicked ;
2017-05-20 15:38:03 +00:00
if ( mb - > get_control ( ) | | selected_list . size ( ) = = 0 ) {
2014-05-11 01:45:52 +00:00
selected_list . insert ( clicked , clicked_main_scene ) ;
2014-05-01 13:47:45 +00:00
} else {
selected_list . clear ( ) ;
2014-05-11 01:45:52 +00:00
selected_list . insert ( clicked , clicked_main_scene ) ;
2014-05-01 13:47:45 +00:00
}
}
2016-07-29 00:33:59 +00:00
_update_project_buttons ( ) ;
2014-02-10 01:10:30 +00:00
2017-05-20 15:38:03 +00:00
if ( mb - > is_doubleclick ( ) )
2018-12-21 11:20:48 +00:00
_open_selected_projects_ask ( ) ; //open if doubleclicked
2014-02-10 01:10:30 +00:00
}
}
2017-05-20 15:38:03 +00:00
void ProjectManager : : _unhandled_input ( const Ref < InputEvent > & p_ev ) {
2016-07-23 19:37:25 +00:00
2017-05-20 15:38:03 +00:00
Ref < InputEventKey > k = p_ev ;
2016-07-23 19:37:25 +00:00
2017-05-20 15:38:03 +00:00
if ( k . is_valid ( ) ) {
2016-07-23 19:37:25 +00:00
2017-05-20 15:38:03 +00:00
if ( ! k - > is_pressed ( ) )
2016-07-23 19:37:25 +00:00
return ;
2017-10-10 15:23:11 +00:00
if ( tabs - > get_current_tab ( ) ! = 0 )
return ;
2016-07-23 19:37:25 +00:00
bool scancode_handled = true ;
2017-05-20 15:38:03 +00:00
switch ( k - > get_scancode ( ) ) {
2016-07-23 19:37:25 +00:00
2017-08-06 13:26:07 +00:00
case KEY_ENTER : {
2016-08-05 14:06:16 +00:00
2018-12-21 11:20:48 +00:00
_open_selected_projects_ask ( ) ;
2016-08-05 14:06:16 +00:00
} break ;
2018-10-02 09:28:18 +00:00
case KEY_DELETE : {
_erase_project ( ) ;
} break ;
2016-07-23 19:37:25 +00:00
case KEY_HOME : {
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
2016-07-23 19:37:25 +00:00
2018-01-18 20:37:17 +00:00
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2016-07-23 19:37:25 +00:00
if ( hb ) {
selected_list . clear ( ) ;
selected_list . insert ( hb - > get_meta ( " name " ) , hb - > get_meta ( " main_scene " ) ) ;
scroll - > set_v_scroll ( 0 ) ;
2016-08-05 14:06:16 +00:00
_update_project_buttons ( ) ;
2016-07-23 19:37:25 +00:00
break ;
}
}
} break ;
case KEY_END : {
2018-01-18 20:37:17 +00:00
for ( int i = scroll_children - > get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2016-07-23 19:37:25 +00:00
2018-01-18 20:37:17 +00:00
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2016-07-23 19:37:25 +00:00
if ( hb ) {
selected_list . clear ( ) ;
selected_list . insert ( hb - > get_meta ( " name " ) , hb - > get_meta ( " main_scene " ) ) ;
2018-01-18 20:37:17 +00:00
scroll - > set_v_scroll ( scroll_children - > get_size ( ) . y ) ;
2016-08-05 14:06:16 +00:00
_update_project_buttons ( ) ;
2016-07-23 19:37:25 +00:00
break ;
}
}
} break ;
case KEY_UP : {
2017-05-20 15:38:03 +00:00
if ( k - > get_shift ( ) )
2016-07-23 19:37:25 +00:00
break ;
if ( selected_list . size ( ) ) {
bool found = false ;
2018-01-18 20:37:17 +00:00
for ( int i = scroll_children - > get_child_count ( ) - 1 ; i > = 0 ; i - - ) {
2016-07-23 19:37:25 +00:00
2018-01-18 20:37:17 +00:00
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2016-07-23 19:37:25 +00:00
if ( ! hb ) continue ;
String current = hb - > get_meta ( " name " ) ;
if ( found ) {
selected_list . clear ( ) ;
selected_list . insert ( current , hb - > get_meta ( " main_scene " ) ) ;
2017-03-29 15:29:38 +00:00
int offset_diff = scroll - > get_v_scroll ( ) - hb - > get_position ( ) . y ;
2016-07-23 19:37:25 +00:00
if ( offset_diff > 0 )
scroll - > set_v_scroll ( scroll - > get_v_scroll ( ) - offset_diff ) ;
2016-08-05 14:06:16 +00:00
_update_project_buttons ( ) ;
2016-07-23 19:37:25 +00:00
break ;
2017-03-05 15:44:50 +00:00
} else if ( current = = selected_list . back ( ) - > key ( ) ) {
2016-07-23 19:37:25 +00:00
found = true ;
}
}
break ;
}
2019-04-05 12:06:16 +00:00
FALLTHROUGH ;
2016-07-23 19:37:25 +00:00
}
case KEY_DOWN : {
2017-05-20 15:38:03 +00:00
if ( k - > get_shift ( ) )
2016-07-23 19:37:25 +00:00
break ;
bool found = selected_list . empty ( ) ;
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
2016-07-23 19:37:25 +00:00
2018-01-18 20:37:17 +00:00
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2016-07-23 19:37:25 +00:00
if ( ! hb ) continue ;
String current = hb - > get_meta ( " name " ) ;
if ( found ) {
selected_list . clear ( ) ;
selected_list . insert ( current , hb - > get_meta ( " main_scene " ) ) ;
int last_y_visible = scroll - > get_v_scroll ( ) + scroll - > get_size ( ) . y ;
2017-03-29 15:29:38 +00:00
int offset_diff = ( hb - > get_position ( ) . y + hb - > get_size ( ) . y ) - last_y_visible ;
2016-07-23 19:37:25 +00:00
if ( offset_diff > 0 )
scroll - > set_v_scroll ( scroll - > get_v_scroll ( ) + offset_diff ) ;
2016-08-05 14:06:16 +00:00
_update_project_buttons ( ) ;
2016-07-23 19:37:25 +00:00
break ;
2017-03-05 15:44:50 +00:00
} else if ( current = = selected_list . back ( ) - > key ( ) ) {
2016-07-23 19:37:25 +00:00
found = true ;
}
}
} break ;
2016-07-26 19:17:41 +00:00
case KEY_F : {
2017-05-20 15:38:03 +00:00
if ( k - > get_command ( ) )
2017-03-05 15:44:50 +00:00
this - > project_filter - > search_box - > grab_focus ( ) ;
else
scancode_handled = false ;
2016-07-26 19:17:41 +00:00
} break ;
2016-07-23 19:37:25 +00:00
default : {
scancode_handled = false ;
} break ;
}
if ( scancode_handled ) {
accept_event ( ) ;
}
}
}
2014-05-20 08:38:18 +00:00
void ProjectManager : : _favorite_pressed ( Node * p_hb ) {
String clicked = p_hb - > get_meta ( " name " ) ;
bool favorite = ! p_hb - > get_meta ( " favorite " ) ;
2017-03-05 15:44:50 +00:00
String proj = clicked . replace ( " ::: " , " :/ " ) ;
proj = proj . replace ( " :: " , " / " ) ;
2014-05-20 08:38:18 +00:00
if ( favorite ) {
2017-03-05 15:44:50 +00:00
EditorSettings : : get_singleton ( ) - > set ( " favorite_projects/ " + clicked , proj ) ;
2014-05-20 08:38:18 +00:00
} else {
2017-03-05 15:44:50 +00:00
EditorSettings : : get_singleton ( ) - > erase ( " favorite_projects/ " + clicked ) ;
2014-05-20 08:38:18 +00:00
}
EditorSettings : : get_singleton ( ) - > save ( ) ;
2014-06-25 03:43:45 +00:00
call_deferred ( " _load_recent_projects " ) ;
2014-05-20 08:38:18 +00:00
}
2014-02-10 01:10:30 +00:00
void ProjectManager : : _load_recent_projects ( ) {
2014-06-11 09:57:13 +00:00
ProjectListFilter : : FilterOption filter_option = project_filter - > get_filter_option ( ) ;
String search_term = project_filter - > get_search_term ( ) ;
2018-01-18 20:37:17 +00:00
while ( scroll_children - > get_child_count ( ) > 0 ) {
memdelete ( scroll_children - > get_child ( 0 ) ) ;
2014-02-10 01:10:30 +00:00
}
2016-07-29 00:33:59 +00:00
Map < String , String > selected_list_copy = selected_list ;
2014-02-10 01:10:30 +00:00
List < PropertyInfo > properties ;
EditorSettings : : get_singleton ( ) - > get_property_list ( & properties ) ;
2017-03-05 15:44:50 +00:00
Color font_color = gui_base - > get_color ( " font_color " , " Tree " ) ;
2014-02-10 01:10:30 +00:00
2018-11-23 19:15:33 +00:00
bool set_ordered_latest_modification ;
ProjectListFilter : : FilterOption filter_order_option = project_order_filter - > get_filter_option ( ) ;
2018-12-12 20:12:41 +00:00
if ( filter_order_option = = ProjectListFilter : : FILTER_NAME ) {
2018-11-23 19:15:33 +00:00
set_ordered_latest_modification = false ;
2018-12-12 20:12:41 +00:00
} else {
2018-11-23 19:15:33 +00:00
set_ordered_latest_modification = true ;
2018-12-12 20:12:41 +00:00
}
EditorSettings : : get_singleton ( ) - > set ( " project_manager/sorting_order " , ( int ) filter_order_option ) ;
2018-11-23 19:15:33 +00:00
2014-05-01 11:30:10 +00:00
List < ProjectItem > projects ;
2014-05-20 08:38:18 +00:00
List < ProjectItem > favorite_projects ;
2014-05-01 11:30:10 +00:00
2017-03-05 15:44:50 +00:00
for ( List < PropertyInfo > : : Element * E = properties . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
String _name = E - > get ( ) . name ;
2014-05-20 08:38:18 +00:00
if ( ! _name . begins_with ( " projects/ " ) & & ! _name . begins_with ( " favorite_projects/ " ) )
2014-02-10 01:10:30 +00:00
continue ;
String path = EditorSettings : : get_singleton ( ) - > get ( _name ) ;
2017-03-05 15:44:50 +00:00
if ( filter_option = = ProjectListFilter : : FILTER_PATH & & search_term ! = " " & & path . findn ( search_term ) = = - 1 )
2014-06-11 09:57:13 +00:00
continue ;
2017-03-05 15:44:50 +00:00
String project = _name . get_slice ( " / " , 1 ) ;
2017-05-01 15:44:52 +00:00
String conf = path . plus_file ( " project.godot " ) ;
2018-12-21 11:20:48 +00:00
int config_version = 0 ; // Assume 0 until we know better
2017-03-05 15:44:50 +00:00
bool favorite = ( _name . begins_with ( " favorite_projects/ " ) ) ? true : false ;
2017-09-11 05:01:20 +00:00
bool grayed = false ;
2014-02-10 01:10:30 +00:00
2014-05-01 11:30:10 +00:00
uint64_t last_modified = 0 ;
2015-10-20 04:14:02 +00:00
if ( FileAccess : : exists ( conf ) ) {
2014-05-01 11:30:10 +00:00
last_modified = FileAccess : : get_modified_time ( conf ) ;
2015-10-20 04:14:02 +00:00
String fscache = path . plus_file ( " .fscache " ) ;
if ( FileAccess : : exists ( fscache ) ) {
uint64_t cache_modified = FileAccess : : get_modified_time ( fscache ) ;
2017-03-05 15:44:50 +00:00
if ( cache_modified > last_modified )
2015-10-20 04:14:02 +00:00
last_modified = cache_modified ;
}
} else {
2017-09-11 05:01:20 +00:00
grayed = true ;
2015-10-20 04:14:02 +00:00
}
2017-09-11 05:01:20 +00:00
2018-12-21 11:20:48 +00:00
ProjectItem item ( project , path , conf , config_version , last_modified , favorite , grayed , set_ordered_latest_modification ) ;
2017-09-11 05:01:20 +00:00
if ( favorite )
favorite_projects . push_back ( item ) ;
else
projects . push_back ( item ) ;
2014-05-01 11:30:10 +00:00
}
projects . sort ( ) ;
2014-05-20 08:38:18 +00:00
favorite_projects . sort ( ) ;
2017-03-05 15:44:50 +00:00
for ( List < ProjectItem > : : Element * E = projects . front ( ) ; E ; ) {
2014-05-20 08:38:18 +00:00
List < ProjectItem > : : Element * next = E - > next ( ) ;
if ( favorite_projects . find ( E - > get ( ) ) ! = NULL )
projects . erase ( E - > get ( ) ) ;
2017-03-05 15:44:50 +00:00
E = next ;
2014-05-20 08:38:18 +00:00
}
2017-03-05 15:44:50 +00:00
for ( List < ProjectItem > : : Element * E = favorite_projects . back ( ) ; E ; E = E - > prev ( ) ) {
2014-05-20 08:38:18 +00:00
projects . push_front ( E - > get ( ) ) ;
}
2017-03-05 15:44:50 +00:00
Ref < Texture > favorite_icon = get_icon ( " Favorites " , " EditorIcons " ) ;
2014-05-01 11:30:10 +00:00
2017-03-05 15:44:50 +00:00
for ( List < ProjectItem > : : Element * E = projects . front ( ) ; E ; E = E - > next ( ) ) {
2014-05-01 11:30:10 +00:00
ProjectItem & item = E - > get ( ) ;
String project = item . project ;
String path = item . path ;
String conf = item . conf ;
2017-03-05 15:44:50 +00:00
Ref < ConfigFile > cf = memnew ( ConfigFile ) ;
2017-09-11 05:01:20 +00:00
Error cf_err = cf - > load ( conf ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
String project_name = TTR ( " Unnamed Project " ) ;
2017-09-11 05:01:20 +00:00
if ( cf_err = = OK & & cf - > has_section_key ( " application " , " config/name " ) ) {
2017-07-21 05:25:22 +00:00
project_name = static_cast < String > ( cf - > get_value ( " application " , " config/name " ) ) . xml_unescape ( ) ;
2014-06-11 09:57:13 +00:00
}
2017-03-05 15:44:50 +00:00
if ( filter_option = = ProjectListFilter : : FILTER_NAME & & search_term ! = " " & & project_name . findn ( search_term ) = = - 1 )
2014-06-11 09:57:13 +00:00
continue ;
Ref < Texture > icon ;
2018-12-21 11:20:48 +00:00
String main_scene ;
if ( cf_err = = OK ) {
item . config_version = ( int ) cf - > get_value ( " " , " config_version " , 0 ) ;
if ( item . config_version > ProjectSettings : : CONFIG_VERSION ) {
// Comes from an incompatible (more recent) Godot version, grey it out
item . grayed = true ;
}
String appicon = cf - > get_value ( " application " , " config/icon " , " " ) ;
2017-03-05 15:44:50 +00:00
if ( appicon ! = " " ) {
2017-05-17 10:36:47 +00:00
Ref < Image > img ;
img . instance ( ) ;
Error err = img - > load ( appicon . replace_first ( " res:// " , path + " / " ) ) ;
2017-03-05 15:44:50 +00:00
if ( err = = OK ) {
2014-02-10 01:10:30 +00:00
2017-08-26 22:27:10 +00:00
Ref < Texture > default_icon = get_icon ( " DefaultProjectIcon " , " EditorIcons " ) ;
img - > resize ( default_icon - > get_width ( ) , default_icon - > get_height ( ) ) ;
2017-03-05 15:44:50 +00:00
Ref < ImageTexture > it = memnew ( ImageTexture ) ;
2014-02-10 01:10:30 +00:00
it - > create_from_image ( img ) ;
2017-03-05 15:44:50 +00:00
icon = it ;
2014-02-10 01:10:30 +00:00
}
}
2018-12-21 11:20:48 +00:00
main_scene = cf - > get_value ( " application " , " run/main_scene " , " " ) ;
2014-02-10 01:10:30 +00:00
}
if ( icon . is_null ( ) ) {
2017-03-05 15:44:50 +00:00
icon = get_icon ( " DefaultProjectIcon " , " EditorIcons " ) ;
2014-02-10 01:10:30 +00:00
}
2016-07-29 00:33:59 +00:00
selected_list_copy . erase ( project ) ;
2018-12-21 11:20:48 +00:00
bool is_favorite = item . favorite ;
bool is_grayed = item . grayed ;
2017-03-05 15:44:50 +00:00
HBoxContainer * hb = memnew ( HBoxContainer ) ;
hb - > set_meta ( " name " , project ) ;
hb - > set_meta ( " main_scene " , main_scene ) ;
hb - > set_meta ( " favorite " , is_favorite ) ;
hb - > connect ( " draw " , this , " _panel_draw " , varray ( hb ) ) ;
hb - > connect ( " gui_input " , this , " _panel_input " , varray ( hb ) ) ;
hb - > add_constant_override ( " separation " , 10 * EDSCALE ) ;
2014-05-20 08:38:18 +00:00
2017-03-05 15:44:50 +00:00
VBoxContainer * favorite_box = memnew ( VBoxContainer ) ;
TextureButton * favorite = memnew ( TextureButton ) ;
2014-05-20 08:38:18 +00:00
favorite - > set_normal_texture ( favorite_icon ) ;
if ( ! is_favorite )
2017-03-05 15:44:50 +00:00
favorite - > set_modulate ( Color ( 1 , 1 , 1 , 0.2 ) ) ;
favorite - > connect ( " pressed " , this , " _favorite_pressed " , varray ( hb ) ) ;
2014-05-20 08:38:18 +00:00
favorite_box - > add_child ( favorite ) ;
2018-01-01 00:58:17 +00:00
favorite_box - > set_alignment ( BoxContainer : : ALIGN_CENTER ) ;
2014-05-20 08:38:18 +00:00
hb - > add_child ( favorite_box ) ;
2017-03-05 15:44:50 +00:00
TextureRect * tf = memnew ( TextureRect ) ;
2014-02-10 01:10:30 +00:00
tf - > set_texture ( icon ) ;
hb - > add_child ( tf ) ;
2014-05-20 08:38:18 +00:00
2014-02-10 01:10:30 +00:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
2017-09-11 05:01:20 +00:00
if ( is_grayed )
vb - > set_modulate ( Color ( 0.5 , 0.5 , 0.5 ) ) ;
2016-11-07 18:39:05 +00:00
vb - > set_name ( " project " ) ;
2017-08-12 07:32:06 +00:00
vb - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2014-02-10 01:10:30 +00:00
hb - > add_child ( vb ) ;
2017-03-05 15:44:50 +00:00
Control * ec = memnew ( Control ) ;
ec - > set_custom_minimum_size ( Size2 ( 0 , 1 ) ) ;
2018-01-04 14:24:20 +00:00
ec - > set_mouse_filter ( MOUSE_FILTER_PASS ) ;
2014-02-10 01:10:30 +00:00
vb - > add_child ( ec ) ;
2017-03-05 15:44:50 +00:00
Label * title = memnew ( Label ( project_name ) ) ;
2017-11-10 01:36:19 +00:00
title - > add_font_override ( " font " , gui_base - > get_font ( " title " , " EditorFonts " ) ) ;
2017-03-05 15:44:50 +00:00
title - > add_color_override ( " font_color " , font_color ) ;
2017-08-12 07:32:06 +00:00
title - > set_clip_text ( true ) ;
2014-02-10 01:10:30 +00:00
vb - > add_child ( title ) ;
2017-12-25 08:57:03 +00:00
HBoxContainer * path_hb = memnew ( HBoxContainer ) ;
path_hb - > set_name ( " path_box " ) ;
path_hb - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
vb - > add_child ( path_hb ) ;
Button * show = memnew ( Button ) ;
show - > set_name ( " show " ) ;
show - > set_icon ( get_icon ( " Filesystem " , " EditorIcons " ) ) ;
show - > set_flat ( true ) ;
show - > set_modulate ( Color ( 1 , 1 , 1 , 0.5 ) ) ;
path_hb - > add_child ( show ) ;
show - > connect ( " pressed " , this , " _show_project " , varray ( path ) ) ;
2018-10-26 19:11:36 +00:00
show - > set_tooltip ( TTR ( " Show in File Manager " ) ) ;
2017-12-25 08:57:03 +00:00
2017-03-05 15:44:50 +00:00
Label * fpath = memnew ( Label ( path ) ) ;
2016-11-07 18:39:05 +00:00
fpath - > set_name ( " path " ) ;
2017-12-25 08:57:03 +00:00
path_hb - > add_child ( fpath ) ;
fpath - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2017-03-05 15:44:50 +00:00
fpath - > set_modulate ( Color ( 1 , 1 , 1 , 0.5 ) ) ;
fpath - > add_color_override ( " font_color " , font_color ) ;
2017-08-12 07:32:06 +00:00
fpath - > set_clip_text ( true ) ;
2014-02-10 01:10:30 +00:00
2018-01-18 20:37:17 +00:00
scroll_children - > add_child ( hb ) ;
2014-02-10 01:10:30 +00:00
}
2016-08-05 14:06:16 +00:00
2017-03-05 15:44:50 +00:00
for ( Map < String , String > : : Element * E = selected_list_copy . front ( ) ; E ; E = E - > next ( ) ) {
2016-07-29 00:33:59 +00:00
String key = E - > key ( ) ;
selected_list . erase ( key ) ;
}
2016-08-05 14:06:16 +00:00
2014-06-11 09:57:13 +00:00
scroll - > set_v_scroll ( 0 ) ;
2016-08-05 14:06:16 +00:00
2016-07-29 00:33:59 +00:00
_update_project_buttons ( ) ;
2015-10-20 04:14:02 +00:00
EditorSettings : : get_singleton ( ) - > save ( ) ;
2016-07-12 00:34:02 +00:00
tabs - > set_current_tab ( 0 ) ;
2014-02-10 01:10:30 +00:00
}
2018-12-21 11:20:48 +00:00
void ProjectManager : : _on_projects_updated ( ) {
2017-09-07 00:04:41 +00:00
_load_recent_projects ( ) ;
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _on_project_created ( const String & dir ) {
2019-02-18 22:03:54 +00:00
project_filter - > clear ( ) ;
2017-03-05 15:44:50 +00:00
bool has_already = false ;
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2017-12-25 08:57:03 +00:00
Label * fpath = Object : : cast_to < Label > ( hb - > get_node ( NodePath ( " project/path_box/path " ) ) ) ;
2017-03-05 15:44:50 +00:00
if ( fpath - > get_text ( ) = = dir ) {
has_already = true ;
2016-11-07 18:39:05 +00:00
break ;
}
}
if ( has_already ) {
2017-09-10 13:37:49 +00:00
_update_scroll_position ( dir ) ;
2016-11-07 18:39:05 +00:00
} else {
_load_recent_projects ( ) ;
2017-09-10 13:37:49 +00:00
_update_scroll_position ( dir ) ;
2016-11-07 18:39:05 +00:00
}
2018-12-21 11:20:48 +00:00
_open_selected_projects_ask ( ) ;
2016-11-07 18:39:05 +00:00
}
2017-09-10 13:37:49 +00:00
void ProjectManager : : _update_scroll_position ( const String & dir ) {
2018-01-18 20:37:17 +00:00
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
2017-12-25 08:57:03 +00:00
Label * fpath = Object : : cast_to < Label > ( hb - > get_node ( NodePath ( " project/path_box/path " ) ) ) ;
2017-03-05 15:44:50 +00:00
if ( fpath - > get_text ( ) = = dir ) {
last_clicked = hb - > get_meta ( " name " ) ;
2016-11-07 18:39:05 +00:00
selected_list . clear ( ) ;
selected_list . insert ( hb - > get_meta ( " name " ) , hb - > get_meta ( " main_scene " ) ) ;
_update_project_buttons ( ) ;
2017-03-05 15:44:50 +00:00
int last_y_visible = scroll - > get_v_scroll ( ) + scroll - > get_size ( ) . y ;
2017-03-29 15:29:38 +00:00
int offset_diff = ( hb - > get_position ( ) . y + hb - > get_size ( ) . y ) - last_y_visible ;
2016-11-07 18:39:05 +00:00
2017-03-05 15:44:50 +00:00
if ( offset_diff > 0 )
scroll - > set_v_scroll ( scroll - > get_v_scroll ( ) + offset_diff ) ;
2016-11-07 18:39:05 +00:00
break ;
}
}
}
2018-12-21 11:20:48 +00:00
void ProjectManager : : _confirm_update_settings ( ) {
_open_selected_projects ( ) ;
}
2014-02-10 01:10:30 +00:00
2018-12-21 11:20:48 +00:00
void ProjectManager : : _open_selected_projects ( ) {
for ( const Map < String , String > : : Element * E = selected_list . front ( ) ; E ; E = E - > next ( ) ) {
2014-05-11 01:45:52 +00:00
const String & selected = E - > key ( ) ;
2017-03-05 15:44:50 +00:00
String path = EditorSettings : : get_singleton ( ) - > get ( " projects/ " + selected ) ;
2018-12-21 11:20:48 +00:00
String conf = path . plus_file ( " project.godot " ) ;
2017-09-11 05:01:20 +00:00
if ( ! FileAccess : : exists ( conf ) ) {
2018-12-21 11:20:48 +00:00
dialog_error - > set_text ( vformat ( TTR ( " Can't open project at '%s'. " ) , path ) ) ;
2017-09-11 05:01:20 +00:00
dialog_error - > popup_centered_minsize ( ) ;
return ;
}
2018-08-24 07:35:07 +00:00
print_line ( " Editing project: " + path + " ( " + selected + " ) " ) ;
2014-02-10 01:10:30 +00:00
2014-05-11 01:45:52 +00:00
List < String > args ;
2014-02-10 01:10:30 +00:00
2017-06-21 09:09:30 +00:00
args . push_back ( " --path " ) ;
2014-05-11 01:45:52 +00:00
args . push_back ( path ) ;
2014-02-10 01:10:30 +00:00
2017-06-21 09:09:30 +00:00
args . push_back ( " --editor " ) ;
2014-02-10 01:10:30 +00:00
2017-09-08 01:01:49 +00:00
if ( OS : : get_singleton ( ) - > is_disable_crash_handler ( ) ) {
args . push_back ( " --disable-crash-handler " ) ;
}
2014-05-11 01:45:52 +00:00
String exec = OS : : get_singleton ( ) - > get_executable_path ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
OS : : ProcessID pid = 0 ;
Error err = OS : : get_singleton ( ) - > execute ( exec , args , false , & pid ) ;
2014-05-11 01:45:52 +00:00
ERR_FAIL_COND ( err ) ;
2014-02-10 01:10:30 +00:00
}
2019-06-09 20:33:50 +00:00
_dim_window ( ) ;
2014-11-06 00:20:42 +00:00
get_tree ( ) - > quit ( ) ;
2014-05-11 01:45:52 +00:00
}
2014-02-10 01:10:30 +00:00
2018-12-21 11:20:48 +00:00
void ProjectManager : : _open_selected_projects_ask ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( selected_list . size ( ) < 1 ) {
2014-05-11 01:45:52 +00:00
return ;
}
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( selected_list . size ( ) > 1 ) {
2016-08-05 14:06:16 +00:00
multi_open_ask - > set_text ( TTR ( " Are you sure to open more than one project? " ) ) ;
2015-04-22 00:30:00 +00:00
multi_open_ask - > popup_centered_minsize ( ) ;
2018-12-21 11:20:48 +00:00
return ;
}
// Update the project settings or don't open
String path = EditorSettings : : get_singleton ( ) - > get ( " projects/ " + selected_list . front ( ) - > key ( ) ) ;
String conf = path . plus_file ( " project.godot " ) ;
// FIXME: We already parse those in _load_recent_projects, we could instead make
// its `projects` list global and reuse its parsed metadata here.
Ref < ConfigFile > cf = memnew ( ConfigFile ) ;
Error cf_err = cf - > load ( conf ) ;
if ( cf_err ! = OK ) {
dialog_error - > set_text ( vformat ( TTR ( " Can't open project at '%s'. " ) , path ) ) ;
dialog_error - > popup_centered_minsize ( ) ;
return ;
}
int config_version = ( int ) cf - > get_value ( " " , " config_version " , 0 ) ;
2019-02-02 01:04:50 +00:00
// Check if the config_version property was empty or 0
if ( config_version = = 0 ) {
2019-03-25 00:54:29 +00:00
ask_update_settings - > set_text ( vformat ( TTR ( " The following project settings file does not specify the version of Godot through which it was created. \n \n %s \n \n If you proceed with opening it, it will be converted to Godot's current configuration file format. \n Warning: You won't be able to open the project with previous versions of the engine anymore. " ) , conf ) ) ;
2019-02-02 01:04:50 +00:00
ask_update_settings - > popup_centered_minsize ( ) ;
return ;
}
2018-12-21 11:20:48 +00:00
// Check if we need to convert project settings from an earlier engine version
if ( config_version < ProjectSettings : : CONFIG_VERSION ) {
2019-03-25 00:54:29 +00:00
ask_update_settings - > set_text ( vformat ( TTR ( " The following project settings file was generated by an older engine version, and needs to be converted for this version: \n \n %s \n \n Do you want to convert it? \n Warning: You won't be able to open the project with previous versions of the engine anymore. " ) , conf ) ) ;
2018-12-21 11:20:48 +00:00
ask_update_settings - > popup_centered_minsize ( ) ;
return ;
}
// Check if the file was generated by a newer, incompatible engine version
if ( config_version > ProjectSettings : : CONFIG_VERSION ) {
dialog_error - > set_text ( vformat ( TTR ( " Can't open project at '%s'. " ) + " \n " + TTR ( " The project settings were created by a newer engine version, whose settings are not compatible with this version. " ) , path ) ) ;
dialog_error - > popup_centered_minsize ( ) ;
return ;
2014-05-11 01:45:52 +00:00
}
2018-12-21 11:20:48 +00:00
// Open if the project is up-to-date
_open_selected_projects ( ) ;
2014-02-10 01:10:30 +00:00
}
2014-05-11 01:45:52 +00:00
void ProjectManager : : _run_project_confirm ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( Map < String , String > : : Element * E = selected_list . front ( ) ; E ; E = E - > next ( ) ) {
2014-02-10 01:10:30 +00:00
2014-05-11 01:45:52 +00:00
const String & selected_main = E - > get ( ) ;
2017-08-07 19:41:04 +00:00
if ( selected_main = = " " ) {
2019-03-25 00:54:29 +00:00
run_error_diag - > set_text ( TTR ( " Can't run project: no main scene defined. \n Please edit the project and set the main scene in the Project Settings under the \" Application \" category. " ) ) ;
2017-08-07 19:41:04 +00:00
run_error_diag - > popup_centered ( ) ;
return ;
}
2014-05-11 01:45:52 +00:00
const String & selected = E - > key ( ) ;
2017-03-05 15:44:50 +00:00
String path = EditorSettings : : get_singleton ( ) - > get ( " projects/ " + selected ) ;
2017-08-07 19:41:04 +00:00
if ( ! DirAccess : : exists ( path + " /.import " ) ) {
run_error_diag - > set_text ( TTR ( " Can't run project: Assets need to be imported. \n Please edit the project to trigger the initial import. " ) ) ;
run_error_diag - > popup_centered ( ) ;
return ;
}
2018-08-24 07:35:07 +00:00
print_line ( " Running project: " + path + " ( " + selected + " ) " ) ;
2014-02-10 01:10:30 +00:00
2014-05-11 01:45:52 +00:00
List < String > args ;
2014-02-10 01:10:30 +00:00
2017-06-21 09:09:30 +00:00
args . push_back ( " --path " ) ;
2014-05-11 01:45:52 +00:00
args . push_back ( path ) ;
2014-02-10 01:10:30 +00:00
2017-09-08 01:01:49 +00:00
if ( OS : : get_singleton ( ) - > is_disable_crash_handler ( ) ) {
args . push_back ( " --disable-crash-handler " ) ;
}
2014-05-11 01:45:52 +00:00
String exec = OS : : get_singleton ( ) - > get_executable_path ( ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
OS : : ProcessID pid = 0 ;
Error err = OS : : get_singleton ( ) - > execute ( exec , args , false , & pid ) ;
2014-05-11 01:45:52 +00:00
ERR_FAIL_COND ( err ) ;
}
}
2014-02-10 01:10:30 +00:00
2014-05-11 01:45:52 +00:00
void ProjectManager : : _run_project ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( selected_list . size ( ) < 1 ) {
2014-05-11 01:45:52 +00:00
return ;
}
2017-03-05 15:44:50 +00:00
if ( selected_list . size ( ) > 1 ) {
2019-03-25 00:54:29 +00:00
multi_run_ask - > set_text ( vformat ( TTR ( " Are you sure to run %d projects at once? " ) , selected_list . size ( ) ) ) ;
2015-04-22 00:30:00 +00:00
multi_run_ask - > popup_centered_minsize ( ) ;
2014-05-11 01:45:52 +00:00
} else {
_run_project_confirm ( ) ;
}
2014-02-10 01:10:30 +00:00
}
2017-12-25 08:57:03 +00:00
void ProjectManager : : _show_project ( const String & p_path ) {
OS : : get_singleton ( ) - > shell_open ( String ( " file:// " ) + p_path ) ;
}
2019-05-26 15:33:51 +00:00
void ProjectManager : : _scan_dir ( const String & path , List < String > * r_projects ) {
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
da - > change_dir ( path ) ;
2014-02-10 01:10:30 +00:00
da - > list_dir_begin ( ) ;
String n = da - > get_next ( ) ;
2017-03-05 15:44:50 +00:00
while ( n ! = String ( ) ) {
2014-02-10 01:10:30 +00:00
if ( da - > current_is_dir ( ) & & ! n . begins_with ( " . " ) ) {
2019-05-26 15:33:51 +00:00
_scan_dir ( da - > get_current_dir ( ) . plus_file ( n ) , r_projects ) ;
2017-05-01 15:44:52 +00:00
} else if ( n = = " project.godot " ) {
2014-02-10 01:10:30 +00:00
r_projects - > push_back ( da - > get_current_dir ( ) ) ;
}
2017-03-05 15:44:50 +00:00
n = da - > get_next ( ) ;
2014-02-10 01:10:30 +00:00
}
da - > list_dir_end ( ) ;
2019-05-26 15:33:51 +00:00
memdelete ( da ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _scan_begin ( const String & p_base ) {
2014-02-10 01:10:30 +00:00
2018-08-24 07:35:07 +00:00
print_line ( " Scanning projects at: " + p_base ) ;
2014-02-10 01:10:30 +00:00
List < String > projects ;
2019-05-26 15:33:51 +00:00
_scan_dir ( p_base , & projects ) ;
2018-08-24 07:35:07 +00:00
print_line ( " Found " + itos ( projects . size ( ) ) + " projects. " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
for ( List < String > : : Element * E = projects . front ( ) ; E ; E = E - > next ( ) ) {
String proj = E - > get ( ) . replace ( " / " , " :: " ) ;
EditorSettings : : get_singleton ( ) - > set ( " projects/ " + proj , E - > get ( ) ) ;
2014-02-10 01:10:30 +00:00
}
EditorSettings : : get_singleton ( ) - > save ( ) ;
_load_recent_projects ( ) ;
}
void ProjectManager : : _scan_projects ( ) {
scan_dir - > popup_centered_ratio ( ) ;
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _new_project ( ) {
2014-02-10 01:10:30 +00:00
2017-08-31 01:08:17 +00:00
npdialog - > set_mode ( ProjectDialog : : MODE_NEW ) ;
2014-02-10 01:10:30 +00:00
npdialog - > show_dialog ( ) ;
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _import_project ( ) {
2014-02-10 01:10:30 +00:00
2017-08-31 01:08:17 +00:00
npdialog - > set_mode ( ProjectDialog : : MODE_IMPORT ) ;
2014-02-10 01:10:30 +00:00
npdialog - > show_dialog ( ) ;
}
2017-09-07 00:04:41 +00:00
void ProjectManager : : _rename_project ( ) {
if ( selected_list . size ( ) = = 0 ) {
return ;
}
for ( Map < String , String > : : Element * E = selected_list . front ( ) ; E ; E = E - > next ( ) ) {
const String & selected = E - > key ( ) ;
String path = EditorSettings : : get_singleton ( ) - > get ( " projects/ " + selected ) ;
npdialog - > set_project_path ( path ) ;
2017-08-31 01:08:17 +00:00
npdialog - > set_mode ( ProjectDialog : : MODE_RENAME ) ;
2017-09-07 00:04:41 +00:00
npdialog - > show_dialog ( ) ;
}
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _erase_project_confirm ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( selected_list . size ( ) = = 0 ) {
2014-02-10 01:10:30 +00:00
return ;
}
2017-03-05 15:44:50 +00:00
for ( Map < String , String > : : Element * E = selected_list . front ( ) ; E ; E = E - > next ( ) ) {
EditorSettings : : get_singleton ( ) - > erase ( " projects/ " + E - > key ( ) ) ;
EditorSettings : : get_singleton ( ) - > erase ( " favorite_projects/ " + E - > key ( ) ) ;
2014-05-01 13:47:45 +00:00
}
2014-02-10 01:10:30 +00:00
EditorSettings : : get_singleton ( ) - > save ( ) ;
2014-05-01 13:47:45 +00:00
selected_list . clear ( ) ;
last_clicked = " " ;
2014-02-10 01:10:30 +00:00
_load_recent_projects ( ) ;
}
2019-02-11 16:44:23 +00:00
void ProjectManager : : _erase_missing_projects_confirm ( ) {
Map < String , String > list_all_projects ;
for ( int i = 0 ; i < scroll_children - > get_child_count ( ) ; i + + ) {
HBoxContainer * hb = Object : : cast_to < HBoxContainer > ( scroll_children - > get_child ( i ) ) ;
if ( hb ) {
list_all_projects . insert ( hb - > get_meta ( " name " ) , hb - > get_meta ( " main_scene " ) ) ;
}
}
if ( list_all_projects . size ( ) = = 0 ) {
return ;
}
int deleted_projects = 0 ;
int remaining_projects = 0 ;
for ( Map < String , String > : : Element * E = list_all_projects . front ( ) ; E ; E = E - > next ( ) ) {
2019-05-01 12:36:04 +00:00
String project_name = E - > key ( ) . replace ( " ::: " , " :/ " ) . replace ( " :: " , " / " ) + " /project.godot " ;
2019-02-11 16:44:23 +00:00
if ( ! FileAccess : : exists ( project_name ) ) {
deleted_projects + + ;
EditorSettings : : get_singleton ( ) - > erase ( " projects/ " + E - > key ( ) ) ;
EditorSettings : : get_singleton ( ) - > erase ( " favorite_projects/ " + E - > key ( ) ) ;
} else {
remaining_projects + + ;
}
}
print_line ( " Deleted " + itos ( deleted_projects ) + " projects, remaining " + itos ( remaining_projects ) + " projects " ) ;
EditorSettings : : get_singleton ( ) - > save ( ) ;
selected_list . clear ( ) ;
last_clicked = " " ;
_load_recent_projects ( ) ;
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _erase_project ( ) {
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
if ( selected_list . size ( ) = = 0 )
2014-02-10 01:10:30 +00:00
return ;
2019-03-25 00:54:29 +00:00
String confirm_message ;
if ( selected_list . size ( ) > = 2 ) {
confirm_message = vformat ( TTR ( " Remove %d projects from the list? \n The project folders' contents won't be modified. " ) , selected_list . size ( ) ) ;
} else {
confirm_message = TTR ( " Remove this project from the list? \n The project folder's contents won't be modified. " ) ;
}
erase_ask - > set_text ( confirm_message ) ;
2015-04-22 00:30:00 +00:00
erase_ask - > popup_centered_minsize ( ) ;
2014-02-10 01:10:30 +00:00
}
2019-02-11 16:44:23 +00:00
void ProjectManager : : _erase_missing_projects ( ) {
erase_missing_ask - > set_text ( TTR ( " Remove all missing projects from the list? (Folders contents will not be modified) " ) ) ;
erase_missing_ask - > popup_centered_minsize ( ) ;
}
2017-10-25 22:02:32 +00:00
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 ) ;
language_btn - > set_text ( lang ) ;
language_btn - > set_icon ( get_icon ( " Environment " , " EditorIcons " ) ) ;
2019-03-25 00:54:29 +00:00
language_restart_ask - > set_text ( TTR ( " Language changed. \n The interface will update after restarting the editor or project manager. " ) ) ;
2017-10-25 22:02:32 +00:00
language_restart_ask - > popup_centered ( ) ;
}
void ProjectManager : : _restart_confirm ( ) {
List < String > args = OS : : get_singleton ( ) - > get_cmdline_args ( ) ;
String exec = OS : : get_singleton ( ) - > get_executable_path ( ) ;
OS : : ProcessID pid = 0 ;
Error err = OS : : get_singleton ( ) - > execute ( exec , args , false , & pid ) ;
ERR_FAIL_COND ( err ) ;
2019-06-09 20:33:50 +00:00
_dim_window ( ) ;
2017-10-25 22:02:32 +00:00
get_tree ( ) - > quit ( ) ;
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _exit_dialog ( ) {
2014-02-10 01:10:30 +00:00
2019-06-09 20:33:50 +00:00
_dim_window ( ) ;
2014-11-06 00:20:42 +00:00
get_tree ( ) - > quit ( ) ;
2014-02-10 01:10:30 +00:00
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _install_project ( const String & p_zip_path , const String & p_title ) {
2016-07-12 00:34:02 +00:00
2017-08-31 01:08:17 +00:00
npdialog - > set_mode ( ProjectDialog : : MODE_INSTALL ) ;
2016-07-12 00:34:02 +00:00
npdialog - > set_zip_path ( p_zip_path ) ;
npdialog - > set_zip_title ( p_title ) ;
npdialog - > show_dialog ( ) ;
}
2017-01-11 03:52:51 +00:00
void ProjectManager : : _files_dropped ( PoolStringArray p_files , int p_screen ) {
2016-07-31 22:59:31 +00:00
Set < String > folders_set ;
DirAccess * da = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2016-07-29 15:06:37 +00:00
for ( int i = 0 ; i < p_files . size ( ) ; i + + ) {
2016-07-31 22:59:31 +00:00
String file = p_files [ i ] ;
folders_set . insert ( da - > dir_exists ( file ) ? file : file . get_base_dir ( ) ) ;
}
memdelete ( da ) ;
2017-03-05 15:44:50 +00:00
if ( folders_set . size ( ) > 0 ) {
2017-01-11 03:52:51 +00:00
PoolStringArray folders ;
2017-03-05 15:44:50 +00:00
for ( Set < String > : : Element * E = folders_set . front ( ) ; E ; E = E - > next ( ) ) {
2016-07-31 22:59:31 +00:00
folders . append ( E - > get ( ) ) ;
}
bool confirm = true ;
2017-03-05 15:44:50 +00:00
if ( folders . size ( ) = = 1 ) {
2016-07-31 22:59:31 +00:00
DirAccess * dir = DirAccess : : create ( DirAccess : : ACCESS_FILESYSTEM ) ;
2017-03-05 15:44:50 +00:00
if ( dir - > change_dir ( folders [ 0 ] ) = = OK ) {
2016-07-31 22:59:31 +00:00
dir - > list_dir_begin ( ) ;
String file = dir - > get_next ( ) ;
2017-03-05 15:44:50 +00:00
while ( confirm & & file ! = String ( ) ) {
2017-05-01 15:44:52 +00:00
if ( ! dir - > current_is_dir ( ) & & file . ends_with ( " project.godot " ) ) {
2016-07-31 22:59:31 +00:00
confirm = false ;
}
file = dir - > get_next ( ) ;
}
dir - > list_dir_end ( ) ;
}
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 ) ) ;
2019-03-25 00:54:29 +00:00
multi_scan_ask - > set_text (
vformat ( TTR ( " Are you sure to scan %s folders for existing Godot projects? \n This could take a while. " ) , folders . size ( ) ) ) ;
2016-07-31 22:59:31 +00:00
multi_scan_ask - > popup_centered_minsize ( ) ;
} else {
_scan_multiple_folders ( folders ) ;
2016-07-29 15:06:37 +00:00
}
}
2016-07-31 22:59:31 +00:00
}
2017-03-05 15:44:50 +00:00
void ProjectManager : : _scan_multiple_folders ( PoolStringArray p_files ) {
2016-07-31 22:59:31 +00:00
for ( int i = 0 ; i < p_files . size ( ) ; i + + ) {
_scan_begin ( p_files . get ( i ) ) ;
2016-07-30 22:10:13 +00:00
}
2016-07-29 15:06:37 +00:00
}
2014-02-10 01:10:30 +00:00
void ProjectManager : : _bind_methods ( ) {
2018-12-21 11:20:48 +00:00
ClassDB : : bind_method ( " _open_selected_projects_ask " , & ProjectManager : : _open_selected_projects_ask ) ;
ClassDB : : bind_method ( " _open_selected_projects " , & ProjectManager : : _open_selected_projects ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _run_project " , & ProjectManager : : _run_project ) ;
ClassDB : : bind_method ( " _run_project_confirm " , & ProjectManager : : _run_project_confirm ) ;
2017-12-25 08:57:03 +00:00
ClassDB : : bind_method ( " _show_project " , & ProjectManager : : _show_project ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _scan_projects " , & ProjectManager : : _scan_projects ) ;
ClassDB : : bind_method ( " _scan_begin " , & ProjectManager : : _scan_begin ) ;
ClassDB : : bind_method ( " _import_project " , & ProjectManager : : _import_project ) ;
ClassDB : : bind_method ( " _new_project " , & ProjectManager : : _new_project ) ;
2017-09-07 00:04:41 +00:00
ClassDB : : bind_method ( " _rename_project " , & ProjectManager : : _rename_project ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _erase_project " , & ProjectManager : : _erase_project ) ;
2019-02-11 16:44:23 +00:00
ClassDB : : bind_method ( " _erase_missing_projects " , & ProjectManager : : _erase_missing_projects ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _erase_project_confirm " , & ProjectManager : : _erase_project_confirm ) ;
2019-02-11 16:44:23 +00:00
ClassDB : : bind_method ( " _erase_missing_projects_confirm " , & ProjectManager : : _erase_missing_projects_confirm ) ;
2017-10-25 22:02:32 +00:00
ClassDB : : bind_method ( " _language_selected " , & ProjectManager : : _language_selected ) ;
ClassDB : : bind_method ( " _restart_confirm " , & ProjectManager : : _restart_confirm ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _exit_dialog " , & ProjectManager : : _exit_dialog ) ;
ClassDB : : bind_method ( " _load_recent_projects " , & ProjectManager : : _load_recent_projects ) ;
2018-12-21 11:20:48 +00:00
ClassDB : : bind_method ( " _on_projects_updated " , & ProjectManager : : _on_projects_updated ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _on_project_created " , & ProjectManager : : _on_project_created ) ;
2017-09-10 13:37:49 +00:00
ClassDB : : bind_method ( " _update_scroll_position " , & ProjectManager : : _update_scroll_position ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( " _panel_draw " , & ProjectManager : : _panel_draw ) ;
ClassDB : : bind_method ( " _panel_input " , & ProjectManager : : _panel_input ) ;
ClassDB : : bind_method ( " _unhandled_input " , & ProjectManager : : _unhandled_input ) ;
ClassDB : : bind_method ( " _favorite_pressed " , & ProjectManager : : _favorite_pressed ) ;
ClassDB : : bind_method ( " _install_project " , & ProjectManager : : _install_project ) ;
ClassDB : : bind_method ( " _files_dropped " , & ProjectManager : : _files_dropped ) ;
2017-11-26 18:31:08 +00:00
ClassDB : : bind_method ( " _open_asset_library " , & ProjectManager : : _open_asset_library ) ;
2018-12-21 11:20:48 +00:00
ClassDB : : bind_method ( " _confirm_update_settings " , & ProjectManager : : _confirm_update_settings ) ;
2017-03-05 15:44:50 +00:00
ClassDB : : bind_method ( D_METHOD ( " _scan_multiple_folders " , " files " ) , & ProjectManager : : _scan_multiple_folders ) ;
2014-02-10 01:10:30 +00:00
}
2017-11-26 18:31:08 +00:00
void ProjectManager : : _open_asset_library ( ) {
asset_library - > disable_community_support ( ) ;
tabs - > set_current_tab ( 1 ) ;
}
2014-02-10 01:10:30 +00:00
ProjectManager : : ProjectManager ( ) {
// load settings
if ( ! EditorSettings : : get_singleton ( ) )
EditorSettings : : create ( ) ;
2016-07-03 22:13:45 +00:00
EditorSettings : : get_singleton ( ) - > set_optimize_save ( false ) ; //just write settings as they came
2016-06-05 21:43:45 +00:00
{
2018-03-22 19:20:42 +00:00
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 ;
2016-06-05 21:43:45 +00:00
}
2018-08-09 09:08:16 +00:00
2018-09-02 09:50:40 +00:00
# ifndef OSX_ENABLED
// The macOS platform implementation uses its own hiDPI window resizing code
// TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below
2018-08-09 09:08:16 +00:00
OS : : get_singleton ( ) - > set_window_size ( OS : : get_singleton ( ) - > get_window_size ( ) * MAX ( 1 , EDSCALE ) ) ;
2018-09-02 09:50:40 +00:00
# endif
2016-06-05 21:43:45 +00:00
}
2017-04-23 08:32:52 +00:00
FileDialog : : set_default_show_hidden_files ( EditorSettings : : get_singleton ( ) - > get ( " filesystem/file_dialog/show_hidden_files " ) ) ;
2014-02-10 01:10:30 +00:00
2017-09-21 22:12:33 +00:00
set_anchors_and_margins_preset ( Control : : PRESET_WIDE ) ;
2016-09-11 13:01:52 +00:00
set_theme ( create_editor_theme ( ) ) ;
2015-12-09 15:35:20 +00:00
2017-03-05 15:44:50 +00:00
gui_base = memnew ( Control ) ;
2016-06-18 05:32:03 +00:00
add_child ( gui_base ) ;
2017-09-21 22:12:33 +00:00
gui_base - > set_anchors_and_margins_preset ( Control : : PRESET_WIDE ) ;
2016-09-20 12:41:57 +00:00
gui_base - > set_theme ( create_custom_theme ( ) ) ;
2015-12-09 15:35:20 +00:00
2017-03-05 15:44:50 +00:00
Panel * panel = memnew ( Panel ) ;
2016-06-18 05:32:03 +00:00
gui_base - > add_child ( panel ) ;
2017-09-21 22:12:33 +00:00
panel - > set_anchors_and_margins_preset ( Control : : PRESET_WIDE ) ;
2019-02-11 21:35:31 +00:00
panel - > add_style_override ( " panel " , gui_base - > get_stylebox ( " Background " , " EditorStyles " ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
2014-02-10 01:10:30 +00:00
panel - > add_child ( vb ) ;
2019-02-11 21:35:31 +00:00
vb - > set_anchors_and_margins_preset ( Control : : PRESET_WIDE , Control : : PRESET_MODE_MINSIZE , 8 * EDSCALE ) ;
2019-02-20 15:08:52 +00:00
vb - > add_constant_override ( " separation " , 8 * EDSCALE ) ;
2014-02-10 01:10:30 +00:00
2016-06-08 12:25:47 +00:00
String cp ;
2018-07-25 01:11:03 +00:00
cp + = 0xA9 ;
2019-01-01 11:53:14 +00:00
OS : : get_singleton ( ) - > set_window_title ( VERSION_NAME + String ( " - " ) + TTR ( " Project Manager " ) + " - " + cp + " 2007-2019 Juan Linietsky, Ariel Manzur & Godot Contributors " ) ;
2016-06-08 12:25:47 +00:00
2017-03-05 15:44:50 +00:00
HBoxContainer * top_hb = memnew ( HBoxContainer ) ;
2016-06-08 12:25:47 +00:00
vb - > add_child ( top_hb ) ;
2017-03-05 15:44:50 +00:00
Label * l = memnew ( Label ) ;
2017-11-19 20:18:01 +00:00
l - > set_text ( VERSION_NAME + String ( " - " ) + TTR ( " Project Manager " ) ) ;
2019-02-11 21:35:31 +00:00
top_hb - > add_child ( l ) ;
2016-06-08 12:25:47 +00:00
top_hb - > add_spacer ( ) ;
2017-03-05 15:44:50 +00:00
l = memnew ( Label ) ;
2017-07-10 08:47:38 +00:00
String hash = String ( VERSION_HASH ) ;
if ( hash . length ( ) ! = 0 )
2019-06-01 11:51:10 +00:00
hash = " . " + hash . left ( 9 ) ;
Refactor version macros and fix related bugs
The previous logic with VERSION_MKSTRING was a bit unwieldy, so there were
several places hardcoding their own variant of the version string, potentially
with bugs (e.g. forgetting the patch number when defined).
The new logic defines:
- VERSION_BRANCH, the main 'major.minor' version (e.g. 3.1)
- VERSION_NUMBER, which can be 'major.minor' or 'major.minor.patch',
depending on whether the latter is defined (e.g. 3.1.4)
- VERSION_FULL_CONFIG, which contains the version status (e.g. stable)
and the module-specific suffix (e.g. mono)
- VERSION_FULL_BUILD, same as above but with build/reference name
(e.g. official, custom_build, mageia, etc.)
Note: Slight change here, as the previous format had the build name
*before* the module-specific suffix; now it's after
- VERSION_FULL_NAME, same as before, so VERSION_FULL_BUILD prefixed
with "Godot v" for readability
Bugs fixed thanks to that:
- Export templates version matching now properly takes VERSION_PATCH
into account by relying on VERSION_FULL_CONFIG.
- ClassDB hash no longer takes the build name into account, but limits
itself to VERSION_FULL_CONFIG (build name is cosmetic, not relevant
for the API hash).
- Docs XML no longer hardcode the VERSION_STATUS, this was annoying.
- Small cleanup in Windows .rc file thanks to new macros.
2018-02-23 18:48:49 +00:00
l - > set_text ( " v " VERSION_FULL_BUILD " " + hash ) ;
2014-02-10 01:10:30 +00:00
l - > set_align ( Label : : ALIGN_CENTER ) ;
2016-06-08 12:25:47 +00:00
top_hb - > add_child ( l ) ;
2014-02-10 01:10:30 +00:00
2017-10-25 22:02:32 +00:00
Control * center_box = memnew ( Control ) ;
center_box - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
vb - > add_child ( center_box ) ;
2017-03-05 15:44:50 +00:00
tabs = memnew ( TabContainer ) ;
2017-10-25 22:02:32 +00:00
center_box - > add_child ( tabs ) ;
tabs - > set_anchors_and_margins_preset ( Control : : PRESET_WIDE ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
HBoxContainer * tree_hb = memnew ( HBoxContainer ) ;
2016-06-08 12:25:47 +00:00
projects_hb = tree_hb ;
projects_hb - > set_name ( TTR ( " Project List " ) ) ;
tabs - > add_child ( tree_hb ) ;
2014-02-10 01:10:30 +00:00
2014-06-11 09:57:13 +00:00
VBoxContainer * search_tree_vb = memnew ( VBoxContainer ) ;
tree_hb - > add_child ( search_tree_vb ) ;
2018-11-23 19:15:33 +00:00
search_tree_vb - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
2014-06-11 09:57:13 +00:00
2018-11-23 19:15:33 +00:00
HBoxContainer * sort_filters = memnew ( HBoxContainer ) ;
Label * sort_label = memnew ( Label ) ;
sort_label - > set_text ( TTR ( " Sort: " ) ) ;
sort_filters - > add_child ( sort_label ) ;
2018-12-12 20:12:41 +00:00
Vector < String > sort_filter_titles ;
sort_filter_titles . push_back ( " Name " ) ;
sort_filter_titles . push_back ( " Last Modified " ) ;
2018-11-23 19:15:33 +00:00
project_order_filter = memnew ( ProjectListFilter ) ;
2018-12-12 20:12:41 +00:00
project_order_filter - > _setup_filters ( sort_filter_titles ) ;
2018-11-23 19:15:33 +00:00
project_order_filter - > set_filter_size ( 150 ) ;
sort_filters - > add_child ( project_order_filter ) ;
project_order_filter - > connect ( " filter_changed " , this , " _load_recent_projects " ) ;
project_order_filter - > set_custom_minimum_size ( Size2 ( 180 , 10 ) * EDSCALE ) ;
2018-12-12 20:12:41 +00:00
int projects_sorting_order = ( int ) EditorSettings : : get_singleton ( ) - > get ( " project_manager/sorting_order " ) ;
project_order_filter - > set_filter_option ( ( ProjectListFilter : : FilterOption ) projects_sorting_order ) ;
2018-11-23 19:15:33 +00:00
sort_filters - > add_spacer ( true ) ;
Label * search_label = memnew ( Label ) ;
2018-12-13 13:16:20 +00:00
search_label - > set_text ( TTR ( " Search: " ) ) ;
2018-11-23 19:15:33 +00:00
sort_filters - > add_child ( search_label ) ;
HBoxContainer * search_filters = memnew ( HBoxContainer ) ;
Vector < String > vec2 ;
vec2 . push_back ( " Name " ) ;
vec2 . push_back ( " Path " ) ;
2014-06-11 09:57:13 +00:00
project_filter = memnew ( ProjectListFilter ) ;
2018-11-23 19:15:33 +00:00
project_filter - > _setup_filters ( vec2 ) ;
project_filter - > add_search_box ( ) ;
search_filters - > add_child ( project_filter ) ;
2014-06-11 09:57:13 +00:00
project_filter - > connect ( " filter_changed " , this , " _load_recent_projects " ) ;
2018-08-09 09:08:16 +00:00
project_filter - > set_custom_minimum_size ( Size2 ( 280 , 10 ) * EDSCALE ) ;
2018-11-23 19:15:33 +00:00
sort_filters - > add_child ( search_filters ) ;
search_tree_vb - > add_child ( sort_filters ) ;
2014-06-11 09:57:13 +00:00
2017-03-05 15:44:50 +00:00
PanelContainer * pc = memnew ( PanelContainer ) ;
pc - > add_style_override ( " panel " , gui_base - > get_stylebox ( " bg " , " Tree " ) ) ;
2014-06-11 09:57:13 +00:00
search_tree_vb - > add_child ( pc ) ;
pc - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
scroll = memnew ( ScrollContainer ) ;
2014-02-10 01:10:30 +00:00
pc - > add_child ( scroll ) ;
scroll - > set_enable_h_scroll ( false ) ;
2017-03-05 15:44:50 +00:00
VBoxContainer * tree_vb = memnew ( VBoxContainer ) ;
2014-06-04 21:15:37 +00:00
tree_hb - > add_child ( tree_vb ) ;
2018-01-18 20:37:17 +00:00
scroll_children = memnew ( VBoxContainer ) ;
scroll_children - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
scroll - > add_child ( scroll_children ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Button * open = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
open - > set_text ( TTR ( " Edit " ) ) ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_child ( open ) ;
2018-12-21 11:20:48 +00:00
open - > connect ( " pressed " , this , " _open_selected_projects_ask " ) ;
2017-03-05 15:44:50 +00:00
open_btn = open ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Button * run = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
run - > set_text ( TTR ( " Run " ) ) ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_child ( run ) ;
2017-03-05 15:44:50 +00:00
run - > connect ( " pressed " , this , " _run_project " ) ;
run_btn = run ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_vb - > add_child ( memnew ( HSeparator ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Button * scan = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
scan - > set_text ( TTR ( " Scan " ) ) ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_child ( scan ) ;
2017-03-05 15:44:50 +00:00
scan - > connect ( " pressed " , this , " _scan_projects " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
tree_vb - > add_child ( memnew ( HSeparator ) ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
scan_dir = memnew ( FileDialog ) ;
2014-02-10 01:10:30 +00:00
scan_dir - > set_access ( FileDialog : : ACCESS_FILESYSTEM ) ;
scan_dir - > set_mode ( FileDialog : : MODE_OPEN_DIR ) ;
2016-07-31 18:46:00 +00:00
scan_dir - > set_title ( TTR ( " Select a Folder to Scan " ) ) ; // must be after mode or it's overridden
2017-03-05 15:44:50 +00:00
scan_dir - > set_current_dir ( EditorSettings : : get_singleton ( ) - > get ( " filesystem/directories/default_project_path " ) ) ;
2016-06-18 05:32:03 +00:00
gui_base - > add_child ( scan_dir ) ;
2017-03-05 15:44:50 +00:00
scan_dir - > connect ( " dir_selected " , this , " _scan_begin " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Button * create = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
create - > set_text ( TTR ( " New Project " ) ) ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_child ( create ) ;
2017-03-05 15:44:50 +00:00
create - > connect ( " pressed " , this , " _new_project " ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
Button * import = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
import - > set_text ( TTR ( " Import " ) ) ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_child ( import ) ;
2017-03-05 15:44:50 +00:00
import - > connect ( " pressed " , this , " _import_project " ) ;
2014-02-10 01:10:30 +00:00
2017-09-07 00:04:41 +00:00
Button * rename = memnew ( Button ) ;
rename - > set_text ( TTR ( " Rename " ) ) ;
tree_vb - > add_child ( rename ) ;
rename - > connect ( " pressed " , this , " _rename_project " ) ;
rename_btn = rename ;
2017-03-05 15:44:50 +00:00
Button * erase = memnew ( Button ) ;
2016-05-04 01:25:37 +00:00
erase - > set_text ( TTR ( " Remove " ) ) ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_child ( erase ) ;
2017-03-05 15:44:50 +00:00
erase - > connect ( " pressed " , this , " _erase_project " ) ;
erase_btn = erase ;
2014-02-10 01:10:30 +00:00
2019-02-11 16:44:23 +00:00
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_btn = erase_missing ;
2014-02-10 01:10:30 +00:00
tree_vb - > add_spacer ( ) ;
2016-06-10 01:47:43 +00:00
if ( StreamPeerSSL : : is_available ( ) ) {
2017-03-05 15:44:50 +00:00
asset_library = memnew ( EditorAssetLibrary ( true ) ) ;
2017-04-20 12:42:35 +00:00
asset_library - > set_name ( TTR ( " Templates " ) ) ;
2016-06-10 01:47:43 +00:00
tabs - > add_child ( asset_library ) ;
2017-03-05 15:44:50 +00:00
asset_library - > connect ( " install_asset " , this , " _install_project " ) ;
2016-06-10 01:47:43 +00:00
} else {
WARN_PRINT ( " Asset Library not available, as it requires SSL to work. " ) ;
}
2014-02-10 01:10:30 +00:00
2017-10-25 22:02:32 +00:00
HBoxContainer * settings_hb = memnew ( HBoxContainer ) ;
settings_hb - > set_alignment ( BoxContainer : : ALIGN_END ) ;
settings_hb - > set_h_grow_direction ( Control : : GROW_DIRECTION_BEGIN ) ;
language_btn = memnew ( OptionButton ) ;
2019-02-11 21:35:31 +00:00
language_btn - > set_flat ( true ) ;
language_btn - > set_focus_mode ( Control : : FOCUS_NONE ) ;
2017-10-25 22:02:32 +00:00
Vector < String > editor_languages ;
List < PropertyInfo > editor_settings_properties ;
EditorSettings : : get_singleton ( ) - > get_property_list ( & editor_settings_properties ) ;
for ( List < PropertyInfo > : : Element * E = editor_settings_properties . front ( ) ; E ; E = E - > next ( ) ) {
PropertyInfo & pi = E - > get ( ) ;
if ( pi . name = = " interface/editor/editor_language " ) {
editor_languages = pi . hint_string . split ( " , " ) ;
}
}
String current_lang = EditorSettings : : get_singleton ( ) - > get ( " interface/editor/editor_language " ) ;
for ( int i = 0 ; i < editor_languages . size ( ) ; i + + ) {
String lang = editor_languages [ i ] ;
String lang_name = TranslationServer : : get_singleton ( ) - > get_locale_name ( lang ) ;
language_btn - > add_item ( lang_name + " [ " + lang + " ] " , i ) ;
language_btn - > set_item_metadata ( i , lang ) ;
if ( current_lang = = lang ) {
language_btn - > select ( i ) ;
language_btn - > set_text ( lang ) ;
}
}
language_btn - > set_icon ( get_icon ( " Environment " , " EditorIcons " ) ) ;
settings_hb - > add_child ( language_btn ) ;
language_btn - > connect ( " item_selected " , this , " _language_selected " ) ;
center_box - > add_child ( settings_hb ) ;
settings_hb - > set_anchors_and_margins_preset ( Control : : PRESET_TOP_RIGHT ) ;
2017-03-05 15:44:50 +00:00
CenterContainer * cc = memnew ( CenterContainer ) ;
Button * cancel = memnew ( Button ) ;
2016-06-08 12:25:47 +00:00
cancel - > set_text ( TTR ( " Exit " ) ) ;
2017-03-05 15:44:50 +00:00
cancel - > set_custom_minimum_size ( Size2 ( 100 , 1 ) * EDSCALE ) ;
2019-03-19 23:47:34 +00:00
# ifndef OSX_ENABLED
// Pressing Command + Q quits the Project Manager
// This is handled by the platform implementation on macOS,
// so only define the shortcut on other platforms
InputEventKey * quit_key = memnew ( InputEventKey ) ;
quit_key - > set_command ( true ) ;
quit_key - > set_scancode ( KEY_Q ) ;
ShortCut * quit_shortcut = memnew ( ShortCut ) ;
quit_shortcut - > set_shortcut ( quit_key ) ;
cancel - > set_shortcut ( quit_shortcut ) ;
# endif
2016-06-08 12:25:47 +00:00
cc - > add_child ( cancel ) ;
2017-03-05 15:44:50 +00:00
cancel - > connect ( " pressed " , this , " _exit_dialog " ) ;
2016-06-08 12:25:47 +00:00
vb - > add_child ( cc ) ;
2017-12-26 23:39:46 +00:00
//////////////////////////////////////////////////////////////
2014-02-10 01:10:30 +00:00
2017-10-25 22:02:32 +00:00
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_cancel ( ) - > set_text ( TTR ( " Continue " ) ) ;
gui_base - > add_child ( language_restart_ask ) ;
2019-02-11 16:44:23 +00:00
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 " ) ;
gui_base - > add_child ( erase_missing_ask ) ;
2017-03-05 15:44:50 +00:00
erase_ask = memnew ( ConfirmationDialog ) ;
2016-05-04 01:25:37 +00:00
erase_ask - > get_ok ( ) - > set_text ( TTR ( " Remove " ) ) ;
2017-03-05 15:44:50 +00:00
erase_ask - > get_ok ( ) - > connect ( " pressed " , this , " _erase_project_confirm " ) ;
2016-06-18 05:32:03 +00:00
gui_base - > add_child ( erase_ask ) ;
2014-02-10 01:10:30 +00:00
2017-03-05 15:44:50 +00:00
multi_open_ask = memnew ( ConfirmationDialog ) ;
2016-05-04 01:25:37 +00:00
multi_open_ask - > get_ok ( ) - > set_text ( TTR ( " Edit " ) ) ;
2018-12-21 11:20:48 +00:00
multi_open_ask - > get_ok ( ) - > connect ( " pressed " , this , " _open_selected_projects " ) ;
2016-06-18 05:32:03 +00:00
gui_base - > add_child ( multi_open_ask ) ;
2014-05-11 01:45:52 +00:00
2017-03-05 15:44:50 +00:00
multi_run_ask = memnew ( ConfirmationDialog ) ;
2016-05-04 01:25:37 +00:00
multi_run_ask - > get_ok ( ) - > set_text ( TTR ( " Run " ) ) ;
2014-05-11 01:45:52 +00:00
multi_run_ask - > get_ok ( ) - > connect ( " pressed " , this , " _run_project_confirm " ) ;
2016-06-18 05:32:03 +00:00
gui_base - > add_child ( multi_run_ask ) ;
2016-08-05 14:06:16 +00:00
2017-03-05 15:44:50 +00:00
multi_scan_ask = memnew ( ConfirmationDialog ) ;
2016-07-31 22:59:31 +00:00
multi_scan_ask - > get_ok ( ) - > set_text ( TTR ( " Scan " ) ) ;
gui_base - > add_child ( multi_scan_ask ) ;
2014-05-11 01:45:52 +00:00
2018-12-21 11:20:48 +00:00
ask_update_settings = memnew ( ConfirmationDialog ) ;
ask_update_settings - > get_ok ( ) - > connect ( " pressed " , this , " _confirm_update_settings " ) ;
gui_base - > add_child ( ask_update_settings ) ;
2014-02-10 01:10:30 +00:00
OS : : get_singleton ( ) - > set_low_processor_usage_mode ( true ) ;
2017-08-31 01:08:17 +00:00
npdialog = memnew ( ProjectDialog ) ;
2016-06-18 05:32:03 +00:00
gui_base - > add_child ( npdialog ) ;
2014-02-10 01:10:30 +00:00
2018-12-21 11:20:48 +00:00
npdialog - > connect ( " projects_updated " , this , " _on_projects_updated " ) ;
2017-03-05 15:44:50 +00:00
npdialog - > connect ( " project_created " , this , " _on_project_created " ) ;
2014-02-10 01:10:30 +00:00
_load_recent_projects ( ) ;
2014-11-01 06:06:29 +00:00
2017-03-05 15:44:50 +00:00
if ( EditorSettings : : get_singleton ( ) - > get ( " filesystem/directories/autoscan_project_path " ) ) {
_scan_begin ( EditorSettings : : get_singleton ( ) - > get ( " filesystem/directories/autoscan_project_path " ) ) ;
2014-11-01 06:06:29 +00:00
}
2014-05-01 13:47:45 +00:00
last_clicked = " " ;
2016-07-29 15:06:37 +00:00
SceneTree : : get_singleton ( ) - > connect ( " files_dropped " , this , " _files_dropped " ) ;
2017-08-07 19:41:04 +00:00
run_error_diag = memnew ( AcceptDialog ) ;
gui_base - > add_child ( run_error_diag ) ;
run_error_diag - > set_title ( TTR ( " Can't run project " ) ) ;
2017-09-11 05:01:20 +00:00
dialog_error = memnew ( AcceptDialog ) ;
gui_base - > add_child ( dialog_error ) ;
2017-11-26 18:31:08 +00:00
open_templates = memnew ( ConfirmationDialog ) ;
2019-03-25 00:54:29 +00:00
open_templates - > set_text ( TTR ( " You currently don't have any projects. \n Would you like to explore official example projects in the Asset Library? " ) ) ;
2017-11-26 18:31:08 +00:00
open_templates - > get_ok ( ) - > set_text ( TTR ( " Open Asset Library " ) ) ;
open_templates - > connect ( " confirmed " , this , " _open_asset_library " ) ;
add_child ( open_templates ) ;
2014-02-10 01:10:30 +00:00
}
ProjectManager : : ~ ProjectManager ( ) {
if ( EditorSettings : : get_singleton ( ) )
EditorSettings : : destroy ( ) ;
}
2014-06-11 09:57:13 +00:00
2018-11-23 19:15:33 +00:00
void ProjectListFilter : : _setup_filters ( Vector < String > options ) {
2014-06-11 09:57:13 +00:00
filter_option - > clear ( ) ;
2018-11-23 19:15:33 +00:00
for ( int i = 0 ; i < options . size ( ) ; i + + )
filter_option - > add_item ( TTR ( options [ i ] ) ) ;
2014-06-11 09:57:13 +00:00
}
void ProjectListFilter : : _search_text_changed ( const String & p_newtext ) {
emit_signal ( " filter_changed " ) ;
}
String ProjectListFilter : : get_search_term ( ) {
return search_box - > get_text ( ) . strip_edges ( ) ;
}
ProjectListFilter : : FilterOption ProjectListFilter : : get_filter_option ( ) {
return _current_filter ;
}
2018-12-12 20:12:41 +00:00
void ProjectListFilter : : set_filter_option ( FilterOption option ) {
filter_option - > select ( ( int ) option ) ;
_filter_option_selected ( 0 ) ;
}
2014-06-11 09:57:13 +00:00
void ProjectListFilter : : _filter_option_selected ( int p_idx ) {
FilterOption selected = ( FilterOption ) ( filter_option - > get_selected ( ) ) ;
2017-03-05 15:44:50 +00:00
if ( _current_filter ! = selected ) {
2014-06-11 09:57:13 +00:00
_current_filter = selected ;
emit_signal ( " filter_changed " ) ;
}
}
2014-06-17 05:38:27 +00:00
void ProjectListFilter : : _notification ( int p_what ) {
2017-11-26 18:31:08 +00:00
2018-11-23 19:15:33 +00:00
if ( p_what = = NOTIFICATION_ENTER_TREE & & has_search_box ) {
2018-08-11 10:04:19 +00:00
search_box - > set_right_icon ( get_icon ( " Search " , " EditorIcons " ) ) ;
2018-07-26 11:45:38 +00:00
search_box - > set_clear_button_enabled ( true ) ;
}
2014-06-17 05:38:27 +00:00
}
2014-06-11 09:57:13 +00:00
void ProjectListFilter : : _bind_methods ( ) {
2017-02-13 11:47:24 +00:00
ClassDB : : bind_method ( D_METHOD ( " _search_text_changed " ) , & ProjectListFilter : : _search_text_changed ) ;
ClassDB : : bind_method ( D_METHOD ( " _filter_option_selected " ) , & ProjectListFilter : : _filter_option_selected ) ;
2014-06-11 09:57:13 +00:00
2017-03-05 15:44:50 +00:00
ADD_SIGNAL ( MethodInfo ( " filter_changed " ) ) ;
2014-06-11 09:57:13 +00:00
}
2018-11-23 19:15:33 +00:00
void ProjectListFilter : : add_search_box ( ) {
search_box = memnew ( LineEdit ) ;
search_box - > connect ( " text_changed " , this , " _search_text_changed " ) ;
search_box - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
add_child ( search_box ) ;
has_search_box = true ;
}
void ProjectListFilter : : set_filter_size ( int h_size ) {
filter_option - > set_custom_minimum_size ( Size2 ( h_size * EDSCALE , 10 * EDSCALE ) ) ;
}
2014-06-11 09:57:13 +00:00
ProjectListFilter : : ProjectListFilter ( ) {
_current_filter = FILTER_NAME ;
filter_option = memnew ( OptionButton ) ;
2018-11-23 19:15:33 +00:00
set_filter_size ( 80 ) ;
2014-06-11 09:57:13 +00:00
filter_option - > set_clip_text ( true ) ;
filter_option - > connect ( " item_selected " , this , " _filter_option_selected " ) ;
add_child ( filter_option ) ;
2018-11-23 19:15:33 +00:00
has_search_box = false ;
2014-06-11 09:57:13 +00:00
}
2019-02-18 22:03:54 +00:00
void ProjectListFilter : : clear ( ) {
if ( has_search_box ) {
search_box - > clear ( ) ;
}
}