2019-06-11 15:31:23 +02:00
/**************************************************************************/
/* editor_feature_profile.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
2019-04-09 00:18:03 +02:00
# include "editor_feature_profile.h"
2020-05-25 13:10:28 +02:00
2021-06-11 14:51:48 +02:00
# include "core/io/dir_access.h"
2019-04-09 00:18:03 +02:00
# include "core/io/json.h"
2022-02-12 02:46:22 +01:00
# include "editor/editor_node.h"
2022-07-29 02:36:26 +02:00
# include "editor/editor_paths.h"
2022-03-03 11:25:11 +01:00
# include "editor/editor_property_name_processor.h"
2019-04-09 00:18:03 +02:00
# include "editor/editor_settings.h"
2023-08-13 02:33:39 +02:00
# include "editor/editor_string_names.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_file_dialog.h"
2024-01-15 13:14:55 +01:00
# include "editor/themes/editor_scale.h"
2019-04-09 00:18:03 +02:00
const char * EditorFeatureProfile : : feature_names [ FEATURE_MAX ] = {
TTRC ( " 3D Editor " ) ,
TTRC ( " Script Editor " ) ,
TTRC ( " Asset Library " ) ,
TTRC ( " Scene Tree Editing " ) ,
TTRC ( " Node Dock " ) ,
2020-05-08 21:51:42 +02:00
TTRC ( " FileSystem Dock " ) ,
TTRC ( " Import Dock " ) ,
2022-11-06 20:53:20 +01:00
TTRC ( " History Dock " ) ,
2019-04-09 00:18:03 +02:00
} ;
2021-05-06 21:24:41 +02:00
const char * EditorFeatureProfile : : feature_descriptions [ FEATURE_MAX ] = {
TTRC ( " Allows to view and edit 3D scenes. " ) ,
TTRC ( " Allows to edit scripts using the integrated script editor. " ) ,
TTRC ( " Provides built-in access to the Asset Library. " ) ,
TTRC ( " Allows editing the node hierarchy in the Scene dock. " ) ,
TTRC ( " Allows to work with signals and groups of the node selected in the Scene dock. " ) ,
TTRC ( " Allows to browse the local file system via a dedicated dock. " ) ,
TTRC ( " Allows to configure import settings for individual assets. Requires the FileSystem dock to function. " ) ,
2022-11-06 20:53:20 +01:00
TTRC ( " Provides an overview of the editor's and each scene's undo history. " ) ,
2021-05-06 21:24:41 +02:00
} ;
2019-04-09 00:18:03 +02:00
const char * EditorFeatureProfile : : feature_identifiers [ FEATURE_MAX ] = {
" 3d " ,
" script " ,
" asset_lib " ,
" scene_tree " ,
" node_dock " ,
2020-05-08 21:51:42 +02:00
" filesystem_dock " ,
" import_dock " ,
2022-11-06 20:53:20 +01:00
" history_dock " ,
2019-04-09 00:18:03 +02:00
} ;
void EditorFeatureProfile : : set_disable_class ( const StringName & p_class , bool p_disabled ) {
if ( p_disabled ) {
disabled_classes . insert ( p_class ) ;
} else {
disabled_classes . erase ( p_class ) ;
}
}
bool EditorFeatureProfile : : is_class_disabled ( const StringName & p_class ) const {
2019-11-07 15:08:01 +01:00
if ( p_class = = StringName ( ) ) {
return false ;
}
return disabled_classes . has ( p_class ) | | is_class_disabled ( ClassDB : : get_parent_class_nocheck ( p_class ) ) ;
2019-04-09 00:18:03 +02:00
}
void EditorFeatureProfile : : set_disable_class_editor ( const StringName & p_class , bool p_disabled ) {
if ( p_disabled ) {
disabled_editors . insert ( p_class ) ;
} else {
disabled_editors . erase ( p_class ) ;
}
}
bool EditorFeatureProfile : : is_class_editor_disabled ( const StringName & p_class ) const {
2019-11-07 15:08:01 +01:00
if ( p_class = = StringName ( ) ) {
return false ;
}
return disabled_editors . has ( p_class ) | | is_class_editor_disabled ( ClassDB : : get_parent_class_nocheck ( p_class ) ) ;
2019-04-09 00:18:03 +02:00
}
void EditorFeatureProfile : : set_disable_class_property ( const StringName & p_class , const StringName & p_property , bool p_disabled ) {
if ( p_disabled ) {
if ( ! disabled_properties . has ( p_class ) ) {
2022-05-19 17:00:06 +02:00
disabled_properties [ p_class ] = HashSet < StringName > ( ) ;
2019-04-09 00:18:03 +02:00
}
disabled_properties [ p_class ] . insert ( p_property ) ;
} else {
ERR_FAIL_COND ( ! disabled_properties . has ( p_class ) ) ;
disabled_properties [ p_class ] . erase ( p_property ) ;
2020-12-15 13:04:21 +01:00
if ( disabled_properties [ p_class ] . is_empty ( ) ) {
2019-04-09 00:18:03 +02:00
disabled_properties . erase ( p_class ) ;
}
}
}
2020-05-14 14:29:06 +02:00
2019-04-09 00:18:03 +02:00
bool EditorFeatureProfile : : is_class_property_disabled ( const StringName & p_class , const StringName & p_property ) const {
if ( ! disabled_properties . has ( p_class ) ) {
return false ;
}
if ( ! disabled_properties [ p_class ] . has ( p_property ) ) {
return false ;
}
return true ;
}
bool EditorFeatureProfile : : has_class_properties_disabled ( const StringName & p_class ) const {
return disabled_properties . has ( p_class ) ;
}
2021-05-27 16:19:33 +02:00
void EditorFeatureProfile : : set_item_collapsed ( const StringName & p_class , bool p_collapsed ) {
if ( p_collapsed ) {
collapsed_classes . insert ( p_class ) ;
} else {
collapsed_classes . erase ( p_class ) ;
}
}
bool EditorFeatureProfile : : is_item_collapsed ( const StringName & p_class ) const {
return collapsed_classes . has ( p_class ) ;
}
2019-04-09 00:18:03 +02:00
void EditorFeatureProfile : : set_disable_feature ( Feature p_feature , bool p_disable ) {
ERR_FAIL_INDEX ( p_feature , FEATURE_MAX ) ;
features_disabled [ p_feature ] = p_disable ;
}
2020-05-14 14:29:06 +02:00
2019-04-09 00:18:03 +02:00
bool EditorFeatureProfile : : is_feature_disabled ( Feature p_feature ) const {
ERR_FAIL_INDEX_V ( p_feature , FEATURE_MAX , false ) ;
return features_disabled [ p_feature ] ;
}
String EditorFeatureProfile : : get_feature_name ( Feature p_feature ) {
ERR_FAIL_INDEX_V ( p_feature , FEATURE_MAX , String ( ) ) ;
return feature_names [ p_feature ] ;
}
2021-05-06 21:24:41 +02:00
String EditorFeatureProfile : : get_feature_description ( Feature p_feature ) {
ERR_FAIL_INDEX_V ( p_feature , FEATURE_MAX , String ( ) ) ;
return feature_descriptions [ p_feature ] ;
}
2019-04-09 00:18:03 +02:00
Error EditorFeatureProfile : : save_to_file ( const String & p_path ) {
2020-12-29 19:12:33 +01:00
Dictionary data ;
data [ " type " ] = " feature_profile " ;
2019-04-09 00:18:03 +02:00
Array dis_classes ;
2022-05-19 01:43:40 +02:00
for ( const StringName & E : disabled_classes ) {
dis_classes . push_back ( String ( E ) ) ;
2019-04-09 00:18:03 +02:00
}
dis_classes . sort ( ) ;
2020-12-29 19:12:33 +01:00
data [ " disabled_classes " ] = dis_classes ;
2019-04-09 00:18:03 +02:00
Array dis_editors ;
2022-05-19 01:43:40 +02:00
for ( const StringName & E : disabled_editors ) {
dis_editors . push_back ( String ( E ) ) ;
2019-04-09 00:18:03 +02:00
}
dis_editors . sort ( ) ;
2020-12-29 19:12:33 +01:00
data [ " disabled_editors " ] = dis_editors ;
2019-04-09 00:18:03 +02:00
Array dis_props ;
2022-05-19 17:00:06 +02:00
for ( KeyValue < StringName , HashSet < StringName > > & E : disabled_properties ) {
2022-05-19 01:43:40 +02:00
for ( const StringName & F : E . value ) {
dis_props . push_back ( String ( E . key ) + " : " + String ( F ) ) ;
2019-04-09 00:18:03 +02:00
}
}
2020-12-29 19:12:33 +01:00
data [ " disabled_properties " ] = dis_props ;
2019-04-09 00:18:03 +02:00
Array dis_features ;
for ( int i = 0 ; i < FEATURE_MAX ; i + + ) {
if ( features_disabled [ i ] ) {
dis_features . push_back ( feature_identifiers [ i ] ) ;
}
}
2020-12-29 19:12:33 +01:00
data [ " disabled_features " ] = dis_features ;
2019-04-09 00:18:03 +02:00
2022-03-23 10:08:58 +01:00
Ref < FileAccess > f = FileAccess : : open ( p_path , FileAccess : : WRITE ) ;
ERR_FAIL_COND_V_MSG ( f . is_null ( ) , ERR_CANT_CREATE , " Cannot create file ' " + p_path + " '. " ) ;
2019-04-09 00:18:03 +02:00
2020-12-29 19:12:33 +01:00
JSON json ;
String text = json . stringify ( data , " \t " ) ;
2019-04-09 00:18:03 +02:00
f - > store_string ( text ) ;
return OK ;
}
Error EditorFeatureProfile : : load_from_file ( const String & p_path ) {
Error err ;
String text = FileAccess : : get_file_as_string ( p_path , & err ) ;
if ( err ! = OK ) {
return err ;
}
2020-12-29 19:12:33 +01:00
JSON json ;
err = json . parse ( text ) ;
2019-04-09 00:18:03 +02:00
if ( err ! = OK ) {
2020-12-29 19:12:33 +01:00
ERR_PRINT ( " Error parsing ' " + p_path + " ' on line " + itos ( json . get_error_line ( ) ) + " : " + json . get_error_message ( ) ) ;
2019-04-09 00:18:03 +02:00
return ERR_PARSE_ERROR ;
}
2020-12-29 19:12:33 +01:00
Dictionary data = json . get_data ( ) ;
2019-04-09 00:18:03 +02:00
2020-12-29 19:12:33 +01:00
if ( ! data . has ( " type " ) | | String ( data [ " type " ] ) ! = " feature_profile " ) {
2019-11-06 17:03:04 +01:00
ERR_PRINT ( " Error parsing ' " + p_path + " ', it's not a feature profile. " ) ;
2019-04-09 00:18:03 +02:00
return ERR_PARSE_ERROR ;
}
disabled_classes . clear ( ) ;
2020-12-29 19:12:33 +01:00
if ( data . has ( " disabled_classes " ) ) {
Array disabled_classes_arr = data [ " disabled_classes " ] ;
2019-04-09 00:18:03 +02:00
for ( int i = 0 ; i < disabled_classes_arr . size ( ) ; i + + ) {
disabled_classes . insert ( disabled_classes_arr [ i ] ) ;
}
}
disabled_editors . clear ( ) ;
2020-12-29 19:12:33 +01:00
if ( data . has ( " disabled_editors " ) ) {
Array disabled_editors_arr = data [ " disabled_editors " ] ;
2019-04-09 00:18:03 +02:00
for ( int i = 0 ; i < disabled_editors_arr . size ( ) ; i + + ) {
disabled_editors . insert ( disabled_editors_arr [ i ] ) ;
}
}
disabled_properties . clear ( ) ;
2020-12-29 19:12:33 +01:00
if ( data . has ( " disabled_properties " ) ) {
Array disabled_properties_arr = data [ " disabled_properties " ] ;
2019-04-09 00:18:03 +02:00
for ( int i = 0 ; i < disabled_properties_arr . size ( ) ; i + + ) {
String s = disabled_properties_arr [ i ] ;
set_disable_class_property ( s . get_slice ( " : " , 0 ) , s . get_slice ( " : " , 1 ) , true ) ;
}
}
2020-12-29 19:12:33 +01:00
if ( data . has ( " disabled_features " ) ) {
Array disabled_features_arr = data [ " disabled_features " ] ;
2019-04-09 00:18:03 +02:00
for ( int i = 0 ; i < FEATURE_MAX ; i + + ) {
bool found = false ;
String f = feature_identifiers [ i ] ;
for ( int j = 0 ; j < disabled_features_arr . size ( ) ; j + + ) {
String fd = disabled_features_arr [ j ] ;
if ( fd = = f ) {
found = true ;
break ;
}
}
features_disabled [ i ] = found ;
}
}
return OK ;
}
void EditorFeatureProfile : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " set_disable_class " , " class_name " , " disable " ) , & EditorFeatureProfile : : set_disable_class ) ;
ClassDB : : bind_method ( D_METHOD ( " is_class_disabled " , " class_name " ) , & EditorFeatureProfile : : is_class_disabled ) ;
ClassDB : : bind_method ( D_METHOD ( " set_disable_class_editor " , " class_name " , " disable " ) , & EditorFeatureProfile : : set_disable_class_editor ) ;
ClassDB : : bind_method ( D_METHOD ( " is_class_editor_disabled " , " class_name " ) , & EditorFeatureProfile : : is_class_editor_disabled ) ;
2019-09-24 11:44:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_disable_class_property " , " class_name " , " property " , " disable " ) , & EditorFeatureProfile : : set_disable_class_property ) ;
ClassDB : : bind_method ( D_METHOD ( " is_class_property_disabled " , " class_name " , " property " ) , & EditorFeatureProfile : : is_class_property_disabled ) ;
2019-04-09 00:18:03 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_disable_feature " , " feature " , " disable " ) , & EditorFeatureProfile : : set_disable_feature ) ;
ClassDB : : bind_method ( D_METHOD ( " is_feature_disabled " , " feature " ) , & EditorFeatureProfile : : is_feature_disabled ) ;
ClassDB : : bind_method ( D_METHOD ( " get_feature_name " , " feature " ) , & EditorFeatureProfile : : _get_feature_name ) ;
ClassDB : : bind_method ( D_METHOD ( " save_to_file " , " path " ) , & EditorFeatureProfile : : save_to_file ) ;
ClassDB : : bind_method ( D_METHOD ( " load_from_file " , " path " ) , & EditorFeatureProfile : : load_from_file ) ;
BIND_ENUM_CONSTANT ( FEATURE_3D ) ;
BIND_ENUM_CONSTANT ( FEATURE_SCRIPT ) ;
BIND_ENUM_CONSTANT ( FEATURE_ASSET_LIB ) ;
BIND_ENUM_CONSTANT ( FEATURE_SCENE_TREE ) ;
BIND_ENUM_CONSTANT ( FEATURE_NODE_DOCK ) ;
BIND_ENUM_CONSTANT ( FEATURE_FILESYSTEM_DOCK ) ;
2020-09-04 10:43:11 +02:00
BIND_ENUM_CONSTANT ( FEATURE_IMPORT_DOCK ) ;
2022-11-06 20:53:20 +01:00
BIND_ENUM_CONSTANT ( FEATURE_HISTORY_DOCK ) ;
2019-04-09 00:18:03 +02:00
BIND_ENUM_CONSTANT ( FEATURE_MAX ) ;
}
2022-09-21 03:36:39 +02:00
EditorFeatureProfile : : EditorFeatureProfile ( ) {
for ( int i = 0 ; i < FEATURE_MAX ; i + + ) {
features_disabled [ i ] = false ;
}
}
2019-04-09 00:18:03 +02:00
//////////////////////////
void EditorFeatureProfileManager : : _notification ( int p_what ) {
2022-02-16 00:52:32 +01:00
switch ( p_what ) {
case NOTIFICATION_READY : {
current_profile = EDITOR_GET ( " _default_feature_profile " ) ;
if ( ! current_profile . is_empty ( ) ) {
current . instantiate ( ) ;
2022-08-30 02:34:01 +02:00
Error err = current - > load_from_file ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( current_profile + " .profile " ) ) ;
2022-02-16 00:52:32 +01:00
if ( err ! = OK ) {
ERR_PRINT ( " Error loading default feature profile: " + current_profile ) ;
current_profile = String ( ) ;
current . unref ( ) ;
}
2019-04-09 00:18:03 +02:00
}
2022-02-16 00:52:32 +01:00
_update_profile_list ( current_profile ) ;
} break ;
2022-08-05 18:17:58 +02:00
case NOTIFICATION_THEME_CHANGED : {
// Make sure that the icons are correctly adjusted if the theme's lightness was switched.
_update_selected_profile ( ) ;
} break ;
2019-04-09 00:18:03 +02:00
}
}
String EditorFeatureProfileManager : : _get_selected_profile ( ) {
int idx = profile_list - > get_selected ( ) ;
if ( idx < 0 ) {
return String ( ) ;
}
return profile_list - > get_item_metadata ( idx ) ;
}
void EditorFeatureProfileManager : : _update_profile_list ( const String & p_select_profile ) {
String selected_profile ;
2021-12-09 10:42:46 +01:00
if ( p_select_profile . is_empty ( ) ) { //default, keep
2019-04-09 00:18:03 +02:00
if ( profile_list - > get_selected ( ) > = 0 ) {
selected_profile = profile_list - > get_item_metadata ( profile_list - > get_selected ( ) ) ;
2022-08-30 02:34:01 +02:00
if ( ! FileAccess : : exists ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( selected_profile + " .profile " ) ) ) {
2019-04-09 00:18:03 +02:00
selected_profile = String ( ) ; //does not exist
}
}
} else {
selected_profile = p_select_profile ;
}
Vector < String > profiles ;
2022-07-29 02:36:26 +02:00
Ref < DirAccess > d = DirAccess : : open ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) ) ;
ERR_FAIL_COND_MSG ( d . is_null ( ) , " Cannot open directory ' " + EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) + " '. " ) ;
2019-09-25 10:28:50 +02:00
2019-04-09 00:18:03 +02:00
d - > list_dir_begin ( ) ;
while ( true ) {
String f = d - > get_next ( ) ;
2021-12-09 10:42:46 +01:00
if ( f . is_empty ( ) ) {
2019-04-09 00:18:03 +02:00
break ;
}
if ( ! d - > current_is_dir ( ) ) {
2020-07-03 15:26:22 +02:00
int last_pos = f . rfind ( " .profile " ) ;
2019-04-09 00:18:03 +02:00
if ( last_pos ! = - 1 ) {
profiles . push_back ( f . substr ( 0 , last_pos ) ) ;
}
}
}
profiles . sort ( ) ;
profile_list - > clear ( ) ;
for ( int i = 0 ; i < profiles . size ( ) ; i + + ) {
String name = profiles [ i ] ;
2021-12-09 10:42:46 +01:00
if ( i = = 0 & & selected_profile . is_empty ( ) ) {
2019-04-09 00:18:03 +02:00
selected_profile = name ;
}
if ( name = = current_profile ) {
2020-03-22 21:52:06 +01:00
name + = " " + TTR ( " (current) " ) ;
2019-04-09 00:18:03 +02:00
}
profile_list - > add_item ( name ) ;
int index = profile_list - > get_item_count ( ) - 1 ;
profile_list - > set_item_metadata ( index , profiles [ i ] ) ;
if ( profiles [ i ] = = selected_profile ) {
profile_list - > select ( index ) ;
}
}
2021-12-09 10:42:46 +01:00
class_list_vbc - > set_visible ( ! selected_profile . is_empty ( ) ) ;
property_list_vbc - > set_visible ( ! selected_profile . is_empty ( ) ) ;
no_profile_selected_help - > set_visible ( selected_profile . is_empty ( ) ) ;
profile_actions [ PROFILE_CLEAR ] - > set_disabled ( current_profile . is_empty ( ) ) ;
profile_actions [ PROFILE_ERASE ] - > set_disabled ( selected_profile . is_empty ( ) ) ;
profile_actions [ PROFILE_EXPORT ] - > set_disabled ( selected_profile . is_empty ( ) ) ;
profile_actions [ PROFILE_SET ] - > set_disabled ( selected_profile . is_empty ( ) ) ;
2019-04-09 00:18:03 +02:00
2021-12-09 10:42:46 +01:00
current_profile_name - > set_text ( ! current_profile . is_empty ( ) ? current_profile : TTR ( " (none) " ) ) ;
2019-04-09 00:18:03 +02:00
_update_selected_profile ( ) ;
}
void EditorFeatureProfileManager : : _profile_action ( int p_action ) {
switch ( p_action ) {
case PROFILE_CLEAR : {
2023-03-04 20:27:56 +01:00
set_current_profile ( " " , false ) ;
2019-04-09 00:18:03 +02:00
} break ;
case PROFILE_SET : {
String selected = _get_selected_profile ( ) ;
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( selected . is_empty ( ) ) ;
2019-04-09 00:18:03 +02:00
if ( selected = = current_profile ) {
2019-06-05 06:12:08 +02:00
return ; // Nothing to do here.
2019-04-09 00:18:03 +02:00
}
2023-03-04 20:27:56 +01:00
set_current_profile ( selected , false ) ;
2019-04-09 00:18:03 +02:00
} break ;
case PROFILE_IMPORT : {
2020-07-11 18:45:19 +02:00
import_profiles - > popup_file_dialog ( ) ;
2019-04-09 00:18:03 +02:00
} break ;
case PROFILE_EXPORT : {
2020-07-11 18:45:19 +02:00
export_profile - > popup_file_dialog ( ) ;
2019-04-09 00:18:03 +02:00
export_profile - > set_current_file ( _get_selected_profile ( ) + " .profile " ) ;
} break ;
case PROFILE_NEW : {
2021-05-06 21:24:41 +02:00
new_profile_dialog - > popup_centered ( Size2 ( 240 , 60 ) * EDSCALE ) ;
2019-04-09 00:18:03 +02:00
new_profile_name - > clear ( ) ;
new_profile_name - > grab_focus ( ) ;
} break ;
case PROFILE_ERASE : {
String selected = _get_selected_profile ( ) ;
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( selected . is_empty ( ) ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
erase_profile_dialog - > set_text ( vformat ( TTR ( " Remove currently selected profile, '%s'? Cannot be undone. " ) , selected ) ) ;
erase_profile_dialog - > popup_centered ( Size2 ( 240 , 60 ) * EDSCALE ) ;
2019-04-09 00:18:03 +02:00
} break ;
}
}
void EditorFeatureProfileManager : : _erase_selected_profile ( ) {
String selected = _get_selected_profile ( ) ;
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( selected . is_empty ( ) ) ;
2022-07-29 02:36:26 +02:00
Ref < DirAccess > da = DirAccess : : open ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) ) ;
ERR_FAIL_COND_MSG ( da . is_null ( ) , " Cannot open directory ' " + EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) + " '. " ) ;
2019-09-25 10:28:50 +02:00
2019-04-09 00:18:03 +02:00
da - > remove ( selected + " .profile " ) ;
if ( selected = = current_profile ) {
_profile_action ( PROFILE_CLEAR ) ;
} else {
_update_profile_list ( ) ;
}
}
void EditorFeatureProfileManager : : _create_new_profile ( ) {
String name = new_profile_name - > get_text ( ) . strip_edges ( ) ;
2022-02-03 17:03:38 +01:00
if ( ! name . is_valid_filename ( ) | | name . contains ( " . " ) ) {
2019-04-09 00:18:03 +02:00
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Profile must be a valid filename and must not contain '.' " ) ) ;
return ;
}
2022-08-30 02:34:01 +02:00
String file = EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( name + " .profile " ) ;
2019-04-09 00:18:03 +02:00
if ( FileAccess : : exists ( file ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Profile with this name already exists. " ) ) ;
return ;
}
Ref < EditorFeatureProfile > new_profile ;
2021-06-18 00:03:09 +02:00
new_profile . instantiate ( ) ;
2019-04-09 00:18:03 +02:00
new_profile - > save_to_file ( file ) ;
_update_profile_list ( name ) ;
2020-03-22 21:52:06 +01:00
// The newly created profile is the first one, make it the current profile automatically.
if ( profile_list - > get_item_count ( ) = = 1 ) {
_profile_action ( PROFILE_SET ) ;
}
2019-04-09 00:18:03 +02:00
}
void EditorFeatureProfileManager : : _profile_selected ( int p_what ) {
_update_selected_profile ( ) ;
}
void EditorFeatureProfileManager : : _fill_classes_from ( TreeItem * p_parent , const String & p_class , const String & p_selected ) {
TreeItem * class_item = class_list - > create_item ( p_parent ) ;
class_item - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
2023-08-01 19:04:28 +02:00
class_item - > set_icon ( 0 , EditorNode : : get_singleton ( ) - > get_class_icon ( p_class ) ) ;
2019-04-09 00:18:03 +02:00
String text = p_class ;
bool disabled = edited - > is_class_disabled ( p_class ) ;
bool disabled_editor = edited - > is_class_editor_disabled ( p_class ) ;
bool disabled_properties = edited - > has_class_properties_disabled ( p_class ) ;
if ( disabled ) {
2024-01-15 13:14:55 +01:00
class_item - > set_custom_color ( 0 , class_list - > get_theme_color ( SNAME ( " font_disabled_color " ) , EditorStringName ( Editor ) ) ) ;
2019-04-09 00:18:03 +02:00
} else if ( disabled_editor & & disabled_properties ) {
text + = " " + TTR ( " (Editor Disabled, Properties Disabled) " ) ;
} else if ( disabled_properties ) {
text + = " " + TTR ( " (Properties Disabled) " ) ;
} else if ( disabled_editor ) {
text + = " " + TTR ( " (Editor Disabled) " ) ;
}
class_item - > set_text ( 0 , text ) ;
class_item - > set_editable ( 0 , true ) ;
class_item - > set_selectable ( 0 , true ) ;
class_item - > set_metadata ( 0 , p_class ) ;
2021-05-27 16:19:33 +02:00
bool collapsed = edited - > is_item_collapsed ( p_class ) ;
class_item - > set_collapsed ( collapsed ) ;
2019-04-09 00:18:03 +02:00
if ( p_class = = p_selected ) {
class_item - > select ( 0 ) ;
}
if ( disabled ) {
2023-08-01 19:04:28 +02:00
// Class disabled, do nothing else (do not show further).
2019-04-09 00:18:03 +02:00
return ;
}
2023-08-01 19:04:28 +02:00
class_item - > set_checked ( 0 , true ) ; // If it's not disabled, it's checked.
2019-04-09 00:18:03 +02:00
List < StringName > child_classes ;
ClassDB : : get_direct_inheriters_from_class ( p_class , & child_classes ) ;
child_classes . sort_custom < StringName : : AlphCompare > ( ) ;
2021-07-24 15:46:25 +02:00
for ( const StringName & name : child_classes ) {
2021-07-16 05:45:57 +02:00
if ( String ( name ) . begins_with ( " Editor " ) | | ClassDB : : get_api_type ( name ) ! = ClassDB : : API_CORE ) {
2019-04-09 00:18:03 +02:00
continue ;
}
_fill_classes_from ( class_item , name , p_selected ) ;
}
}
void EditorFeatureProfileManager : : _class_list_item_selected ( ) {
2020-05-14 16:41:43 +02:00
if ( updating_features ) {
2019-04-09 00:18:03 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-04-09 00:18:03 +02:00
property_list - > clear ( ) ;
TreeItem * item = class_list - > get_selected ( ) ;
if ( ! item ) {
return ;
}
Variant md = item - > get_metadata ( 0 ) ;
2021-05-06 21:24:41 +02:00
if ( md . get_type ( ) = = Variant : : STRING | | md . get_type ( ) = = Variant : : STRING_NAME ) {
2023-09-21 04:54:51 +02:00
String text = description_bit - > get_class_description ( md ) ;
if ( ! text . is_empty ( ) ) {
// Display both class name and description, since the help bit may be displayed
// far away from the location (especially if the dialog was resized to be taller).
description_bit - > set_text ( vformat ( " [b]%s[/b]: %s " , md , text ) ) ;
description_bit - > get_rich_text ( ) - > set_self_modulate ( Color ( 1 , 1 , 1 , 1 ) ) ;
} else {
// Use nested `vformat()` as translators shouldn't interfere with BBCode tags.
description_bit - > set_text ( vformat ( TTR ( " No description available for %s. " ) , vformat ( " [b]%s[/b] " , md ) ) ) ;
description_bit - > get_rich_text ( ) - > set_self_modulate ( Color ( 1 , 1 , 1 , 0.5 ) ) ;
2021-05-06 21:24:41 +02:00
}
} else if ( md . get_type ( ) = = Variant : : INT ) {
2023-09-21 04:54:51 +02:00
String feature_description = EditorFeatureProfile : : get_feature_description ( EditorFeatureProfile : : Feature ( ( int ) md ) ) ;
description_bit - > set_text ( vformat ( " [b]%s[/b]: %s " , TTR ( item - > get_text ( 0 ) ) , TTRGET ( feature_description ) ) ) ;
description_bit - > get_rich_text ( ) - > set_self_modulate ( Color ( 1 , 1 , 1 , 1 ) ) ;
2021-05-06 21:24:41 +02:00
return ;
} else {
2019-04-09 00:18:03 +02:00
return ;
}
String class_name = md ;
if ( edited - > is_class_disabled ( class_name ) ) {
return ;
}
updating_features = true ;
TreeItem * root = property_list - > create_item ( ) ;
TreeItem * options = property_list - > create_item ( root ) ;
options - > set_text ( 0 , TTR ( " Class Options: " ) ) ;
{
TreeItem * option = property_list - > create_item ( options ) ;
option - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
option - > set_editable ( 0 , true ) ;
option - > set_selectable ( 0 , true ) ;
2019-04-09 01:20:20 +02:00
option - > set_checked ( 0 , ! edited - > is_class_editor_disabled ( class_name ) ) ;
option - > set_text ( 0 , TTR ( " Enable Contextual Editor " ) ) ;
2019-04-09 00:18:03 +02:00
option - > set_metadata ( 0 , CLASS_OPTION_DISABLE_EDITOR ) ;
}
List < PropertyInfo > props ;
ClassDB : : get_property_list ( class_name , & props , true ) ;
2022-02-07 11:55:17 +01:00
bool has_editor_props = false ;
for ( const PropertyInfo & E : props ) {
if ( E . usage & PROPERTY_USAGE_EDITOR ) {
has_editor_props = true ;
break ;
}
}
if ( has_editor_props ) {
2021-05-06 21:24:41 +02:00
TreeItem * properties = property_list - > create_item ( root ) ;
properties - > set_text ( 0 , TTR ( " Class Properties: " ) ) ;
2022-03-23 02:46:59 +01:00
const EditorPropertyNameProcessor : : Style text_style = EditorPropertyNameProcessor : : get_settings_style ( ) ;
const EditorPropertyNameProcessor : : Style tooltip_style = EditorPropertyNameProcessor : : get_tooltip_style ( text_style ) ;
2021-07-24 15:46:25 +02:00
for ( const PropertyInfo & E : props ) {
2021-07-16 05:45:57 +02:00
String name = E . name ;
if ( ! ( E . usage & PROPERTY_USAGE_EDITOR ) ) {
2021-05-06 21:24:41 +02:00
continue ;
}
2022-03-23 02:46:59 +01:00
const String text = EditorPropertyNameProcessor : : get_singleton ( ) - > process_name ( name , text_style ) ;
const String tooltip = EditorPropertyNameProcessor : : get_singleton ( ) - > process_name ( name , tooltip_style ) ;
2021-05-06 21:24:41 +02:00
TreeItem * property = property_list - > create_item ( properties ) ;
property - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
property - > set_editable ( 0 , true ) ;
property - > set_selectable ( 0 , true ) ;
property - > set_checked ( 0 , ! edited - > is_class_property_disabled ( class_name , name ) ) ;
2022-03-23 02:46:59 +01:00
property - > set_text ( 0 , text ) ;
2022-08-29 15:55:49 +02:00
property - > set_tooltip_text ( 0 , tooltip ) ;
2021-05-06 21:24:41 +02:00
property - > set_metadata ( 0 , name ) ;
2021-07-16 05:45:57 +02:00
String icon_type = Variant : : get_type_name ( E . type ) ;
2021-05-06 21:24:41 +02:00
property - > set_icon ( 0 , EditorNode : : get_singleton ( ) - > get_class_icon ( icon_type ) ) ;
2020-05-14 16:41:43 +02:00
}
2019-04-09 00:18:03 +02:00
}
updating_features = false ;
}
void EditorFeatureProfileManager : : _class_list_item_edited ( ) {
2020-05-14 16:41:43 +02:00
if ( updating_features ) {
2019-04-09 00:18:03 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-04-09 00:18:03 +02:00
TreeItem * item = class_list - > get_edited ( ) ;
if ( ! item ) {
return ;
}
bool checked = item - > is_checked ( 0 ) ;
Variant md = item - > get_metadata ( 0 ) ;
2020-02-20 22:58:05 +01:00
if ( md . get_type ( ) = = Variant : : STRING | | md . get_type ( ) = = Variant : : STRING_NAME ) {
2019-04-09 00:18:03 +02:00
String class_selected = md ;
edited - > set_disable_class ( class_selected , ! checked ) ;
_save_and_update ( ) ;
_update_selected_profile ( ) ;
} else if ( md . get_type ( ) = = Variant : : INT ) {
int feature_selected = md ;
edited - > set_disable_feature ( EditorFeatureProfile : : Feature ( feature_selected ) , ! checked ) ;
_save_and_update ( ) ;
}
}
2021-05-27 16:19:33 +02:00
void EditorFeatureProfileManager : : _class_list_item_collapsed ( Object * p_item ) {
if ( updating_features ) {
return ;
}
TreeItem * item = Object : : cast_to < TreeItem > ( p_item ) ;
if ( ! item ) {
return ;
}
Variant md = item - > get_metadata ( 0 ) ;
if ( md . get_type ( ) ! = Variant : : STRING & & md . get_type ( ) ! = Variant : : STRING_NAME ) {
return ;
}
String class_name = md ;
bool collapsed = item - > is_collapsed ( ) ;
edited - > set_item_collapsed ( class_name , collapsed ) ;
}
2019-04-09 00:18:03 +02:00
void EditorFeatureProfileManager : : _property_item_edited ( ) {
2020-05-14 16:41:43 +02:00
if ( updating_features ) {
2019-04-09 00:18:03 +02:00
return ;
2020-05-14 16:41:43 +02:00
}
2019-04-09 00:18:03 +02:00
TreeItem * class_item = class_list - > get_selected ( ) ;
if ( ! class_item ) {
return ;
}
Variant md = class_item - > get_metadata ( 0 ) ;
2020-02-20 22:58:05 +01:00
if ( md . get_type ( ) ! = Variant : : STRING & & md . get_type ( ) ! = Variant : : STRING_NAME ) {
2019-04-09 00:18:03 +02:00
return ;
}
String class_name = md ;
TreeItem * item = property_list - > get_edited ( ) ;
if ( ! item ) {
return ;
}
bool checked = item - > is_checked ( 0 ) ;
md = item - > get_metadata ( 0 ) ;
2020-02-20 22:58:05 +01:00
if ( md . get_type ( ) = = Variant : : STRING | | md . get_type ( ) = = Variant : : STRING_NAME ) {
2019-04-09 00:18:03 +02:00
String property_selected = md ;
edited - > set_disable_class_property ( class_name , property_selected , ! checked ) ;
_save_and_update ( ) ;
_update_selected_profile ( ) ;
} else if ( md . get_type ( ) = = Variant : : INT ) {
int feature_selected = md ;
switch ( feature_selected ) {
case CLASS_OPTION_DISABLE_EDITOR : {
2019-04-09 01:20:20 +02:00
edited - > set_disable_class_editor ( class_name , ! checked ) ;
2019-04-09 00:18:03 +02:00
_save_and_update ( ) ;
_update_selected_profile ( ) ;
} break ;
}
}
}
void EditorFeatureProfileManager : : _update_selected_profile ( ) {
String class_selected ;
int feature_selected = - 1 ;
if ( class_list - > get_selected ( ) ) {
Variant md = class_list - > get_selected ( ) - > get_metadata ( 0 ) ;
2020-02-20 22:58:05 +01:00
if ( md . get_type ( ) = = Variant : : STRING | | md . get_type ( ) = = Variant : : STRING_NAME ) {
2019-04-09 00:18:03 +02:00
class_selected = md ;
} else if ( md . get_type ( ) = = Variant : : INT ) {
feature_selected = md ;
}
}
class_list - > clear ( ) ;
String profile = _get_selected_profile ( ) ;
2022-09-21 03:36:39 +02:00
profile_actions [ PROFILE_SET ] - > set_disabled ( profile = = current_profile ) ;
2021-12-09 10:42:46 +01:00
if ( profile . is_empty ( ) ) { //nothing selected, nothing edited
2019-04-09 00:18:03 +02:00
property_list - > clear ( ) ;
edited . unref ( ) ;
return ;
}
if ( profile = = current_profile ) {
edited = current ; //reuse current profile (which is what editor uses)
ERR_FAIL_COND ( current . is_null ( ) ) ; //nothing selected, current should never be null
} else {
//reload edited, if different from current
2021-06-18 00:03:09 +02:00
edited . instantiate ( ) ;
2022-08-30 02:34:01 +02:00
Error err = edited - > load_from_file ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( profile + " .profile " ) ) ;
ERR_FAIL_COND_MSG ( err ! = OK , " Error when loading editor feature profile from file ' " + EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( profile + " .profile " ) + " '. " ) ;
2019-04-09 00:18:03 +02:00
}
updating_features = true ;
TreeItem * root = class_list - > create_item ( ) ;
TreeItem * features = class_list - > create_item ( root ) ;
2022-09-22 09:25:47 +02:00
TreeItem * last_feature = nullptr ;
2021-07-31 19:08:07 +02:00
features - > set_text ( 0 , TTR ( " Main Features: " ) ) ;
2019-04-09 00:18:03 +02:00
for ( int i = 0 ; i < EditorFeatureProfile : : FEATURE_MAX ; i + + ) {
2020-05-08 21:51:42 +02:00
TreeItem * feature ;
if ( i = = EditorFeatureProfile : : FEATURE_IMPORT_DOCK ) {
feature = class_list - > create_item ( last_feature ) ;
} else {
feature = class_list - > create_item ( features ) ;
last_feature = feature ;
}
2019-04-09 00:18:03 +02:00
feature - > set_cell_mode ( 0 , TreeItem : : CELL_MODE_CHECK ) ;
feature - > set_text ( 0 , TTRGET ( EditorFeatureProfile : : get_feature_name ( EditorFeatureProfile : : Feature ( i ) ) ) ) ;
feature - > set_selectable ( 0 , true ) ;
feature - > set_editable ( 0 , true ) ;
feature - > set_metadata ( 0 , i ) ;
if ( ! edited - > is_feature_disabled ( EditorFeatureProfile : : Feature ( i ) ) ) {
feature - > set_checked ( 0 , true ) ;
}
if ( i = = feature_selected ) {
feature - > select ( 0 ) ;
}
}
TreeItem * classes = class_list - > create_item ( root ) ;
2021-07-31 19:08:07 +02:00
classes - > set_text ( 0 , TTR ( " Nodes and Classes: " ) ) ;
2019-04-09 00:18:03 +02:00
_fill_classes_from ( classes , " Node " , class_selected ) ;
_fill_classes_from ( classes , " Resource " , class_selected ) ;
updating_features = false ;
_class_list_item_selected ( ) ;
}
void EditorFeatureProfileManager : : _import_profiles ( const Vector < String > & p_paths ) {
//test it first
for ( int i = 0 ; i < p_paths . size ( ) ; i + + ) {
Ref < EditorFeatureProfile > profile ;
2021-06-18 00:03:09 +02:00
profile . instantiate ( ) ;
2019-04-09 00:18:03 +02:00
Error err = profile - > load_from_file ( p_paths [ i ] ) ;
String basefile = p_paths [ i ] . get_file ( ) ;
if ( err ! = OK ) {
EditorNode : : get_singleton ( ) - > show_warning ( vformat ( TTR ( " File '%s' format is invalid, import aborted. " ) , basefile ) ) ;
return ;
}
2022-08-30 02:34:01 +02:00
String dst_file = EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( basefile ) ;
2019-04-09 00:18:03 +02:00
if ( FileAccess : : exists ( dst_file ) ) {
2019-06-17 14:11:49 +02:00
EditorNode : : get_singleton ( ) - > show_warning ( vformat ( TTR ( " Profile '%s' already exists. Remove it first before importing, import aborted. " ) , basefile . get_basename ( ) ) ) ;
2019-04-09 00:18:03 +02:00
return ;
}
}
//do it second
for ( int i = 0 ; i < p_paths . size ( ) ; i + + ) {
Ref < EditorFeatureProfile > profile ;
2021-06-18 00:03:09 +02:00
profile . instantiate ( ) ;
2019-04-09 00:18:03 +02:00
Error err = profile - > load_from_file ( p_paths [ i ] ) ;
ERR_CONTINUE ( err ! = OK ) ;
String basefile = p_paths [ i ] . get_file ( ) ;
2022-08-30 02:34:01 +02:00
String dst_file = EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( basefile ) ;
2019-04-09 00:18:03 +02:00
profile - > save_to_file ( dst_file ) ;
}
_update_profile_list ( ) ;
2020-03-22 21:52:06 +01:00
// The newly imported profile is the first one, make it the current profile automatically.
if ( profile_list - > get_item_count ( ) = = 1 ) {
_profile_action ( PROFILE_SET ) ;
}
2019-04-09 00:18:03 +02:00
}
void EditorFeatureProfileManager : : _export_profile ( const String & p_path ) {
ERR_FAIL_COND ( edited . is_null ( ) ) ;
Error err = edited - > save_to_file ( p_path ) ;
if ( err ! = OK ) {
EditorNode : : get_singleton ( ) - > show_warning ( vformat ( TTR ( " Error saving profile to path: '%s'. " ) , p_path ) ) ;
}
}
void EditorFeatureProfileManager : : _save_and_update ( ) {
String edited_path = _get_selected_profile ( ) ;
2021-12-09 10:42:46 +01:00
ERR_FAIL_COND ( edited_path . is_empty ( ) ) ;
2019-04-09 00:18:03 +02:00
ERR_FAIL_COND ( edited . is_null ( ) ) ;
2022-08-30 02:34:01 +02:00
edited - > save_to_file ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) . path_join ( edited_path + " .profile " ) ) ;
2019-04-09 00:18:03 +02:00
if ( edited = = current ) {
update_timer - > start ( ) ;
}
}
void EditorFeatureProfileManager : : _emit_current_profile_changed ( ) {
2021-07-17 23:22:52 +02:00
emit_signal ( SNAME ( " current_feature_profile_changed " ) ) ;
2019-04-09 00:18:03 +02:00
}
void EditorFeatureProfileManager : : notify_changed ( ) {
_emit_current_profile_changed ( ) ;
}
Ref < EditorFeatureProfile > EditorFeatureProfileManager : : get_current_profile ( ) {
return current ;
}
2023-03-04 20:27:56 +01:00
String EditorFeatureProfileManager : : get_current_profile_name ( ) const {
return current_profile ;
}
void EditorFeatureProfileManager : : set_current_profile ( const String & p_profile_name , bool p_validate_profile ) {
if ( p_validate_profile & & ! p_profile_name . is_empty ( ) ) {
// Profile may not exist.
Ref < DirAccess > da = DirAccess : : open ( EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) ) ;
ERR_FAIL_COND_MSG ( da . is_null ( ) , " Cannot open directory ' " + EditorPaths : : get_singleton ( ) - > get_feature_profiles_dir ( ) + " '. " ) ;
ERR_FAIL_COND_MSG ( ! da - > file_exists ( p_profile_name + " .profile " ) , " Feature profile ' " + p_profile_name + " ' does not exist. " ) ;
// Change profile selection to emulate the UI interaction. Otherwise, the wrong profile would get activated.
// FIXME: Ideally, _update_selected_profile() should not rely on the user interface state to function properly.
for ( int i = 0 ; i < profile_list - > get_item_count ( ) ; i + + ) {
if ( profile_list - > get_item_metadata ( i ) = = p_profile_name ) {
profile_list - > select ( i ) ;
break ;
}
}
_update_selected_profile ( ) ;
}
// Store in editor settings.
EditorSettings : : get_singleton ( ) - > set ( " _default_feature_profile " , p_profile_name ) ;
EditorSettings : : get_singleton ( ) - > save ( ) ;
current_profile = p_profile_name ;
if ( p_profile_name . is_empty ( ) ) {
current . unref ( ) ;
} else {
current = edited ;
}
_update_profile_list ( ) ;
_emit_current_profile_changed ( ) ;
}
2020-04-02 01:20:12 +02:00
EditorFeatureProfileManager * EditorFeatureProfileManager : : singleton = nullptr ;
2019-04-09 00:18:03 +02:00
void EditorFeatureProfileManager : : _bind_methods ( ) {
ADD_SIGNAL ( MethodInfo ( " current_feature_profile_changed " ) ) ;
}
EditorFeatureProfileManager : : EditorFeatureProfileManager ( ) {
VBoxContainer * main_vbc = memnew ( VBoxContainer ) ;
add_child ( main_vbc ) ;
HBoxContainer * name_hbc = memnew ( HBoxContainer ) ;
current_profile_name = memnew ( LineEdit ) ;
name_hbc - > add_child ( current_profile_name ) ;
2020-03-22 21:52:06 +01:00
current_profile_name - > set_text ( TTR ( " (none) " ) ) ;
2019-04-09 00:18:03 +02:00
current_profile_name - > set_editable ( false ) ;
2020-03-06 18:00:16 +01:00
current_profile_name - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2021-05-06 21:24:41 +02:00
profile_actions [ PROFILE_CLEAR ] = memnew ( Button ( TTR ( " Reset to Default " ) ) ) ;
2019-04-09 00:18:03 +02:00
name_hbc - > add_child ( profile_actions [ PROFILE_CLEAR ] ) ;
profile_actions [ PROFILE_CLEAR ] - > set_disabled ( true ) ;
2022-07-28 22:56:41 +02:00
profile_actions [ PROFILE_CLEAR ] - > connect ( " pressed " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_action ) . bind ( PROFILE_CLEAR ) ) ;
2019-04-09 00:18:03 +02:00
2019-06-05 06:12:08 +02:00
main_vbc - > add_margin_child ( TTR ( " Current Profile: " ) , name_hbc ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
main_vbc - > add_child ( memnew ( HSeparator ) ) ;
2019-04-09 00:18:03 +02:00
HBoxContainer * profiles_hbc = memnew ( HBoxContainer ) ;
profile_list = memnew ( OptionButton ) ;
2020-03-06 18:00:16 +01:00
profile_list - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2023-03-28 17:02:02 +02:00
profile_list - > set_auto_translate ( false ) ;
2019-04-09 00:18:03 +02:00
profiles_hbc - > add_child ( profile_list ) ;
2020-02-21 18:28:45 +01:00
profile_list - > connect ( " item_selected " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_selected ) ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
profile_actions [ PROFILE_NEW ] = memnew ( Button ( TTR ( " Create Profile " ) ) ) ;
profiles_hbc - > add_child ( profile_actions [ PROFILE_NEW ] ) ;
2022-07-28 22:56:41 +02:00
profile_actions [ PROFILE_NEW ] - > connect ( " pressed " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_action ) . bind ( PROFILE_NEW ) ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
profile_actions [ PROFILE_ERASE ] = memnew ( Button ( TTR ( " Remove Profile " ) ) ) ;
2019-04-09 00:18:03 +02:00
profiles_hbc - > add_child ( profile_actions [ PROFILE_ERASE ] ) ;
profile_actions [ PROFILE_ERASE ] - > set_disabled ( true ) ;
2022-07-28 22:56:41 +02:00
profile_actions [ PROFILE_ERASE ] - > connect ( " pressed " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_action ) . bind ( PROFILE_ERASE ) ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
main_vbc - > add_margin_child ( TTR ( " Available Profiles: " ) , profiles_hbc ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
HBoxContainer * current_profile_hbc = memnew ( HBoxContainer ) ;
profile_actions [ PROFILE_SET ] = memnew ( Button ( TTR ( " Make Current " ) ) ) ;
current_profile_hbc - > add_child ( profile_actions [ PROFILE_SET ] ) ;
profile_actions [ PROFILE_SET ] - > set_disabled ( true ) ;
2022-07-28 22:56:41 +02:00
profile_actions [ PROFILE_SET ] - > connect ( " pressed " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_action ) . bind ( PROFILE_SET ) ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
current_profile_hbc - > add_child ( memnew ( VSeparator ) ) ;
2019-04-09 00:18:03 +02:00
profile_actions [ PROFILE_IMPORT ] = memnew ( Button ( TTR ( " Import " ) ) ) ;
2021-05-06 21:24:41 +02:00
current_profile_hbc - > add_child ( profile_actions [ PROFILE_IMPORT ] ) ;
2022-07-28 22:56:41 +02:00
profile_actions [ PROFILE_IMPORT ] - > connect ( " pressed " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_action ) . bind ( PROFILE_IMPORT ) ) ;
2019-04-09 00:18:03 +02:00
profile_actions [ PROFILE_EXPORT ] = memnew ( Button ( TTR ( " Export " ) ) ) ;
2021-05-06 21:24:41 +02:00
current_profile_hbc - > add_child ( profile_actions [ PROFILE_EXPORT ] ) ;
2019-04-09 00:18:03 +02:00
profile_actions [ PROFILE_EXPORT ] - > set_disabled ( true ) ;
2022-07-28 22:56:41 +02:00
profile_actions [ PROFILE_EXPORT ] - > connect ( " pressed " , callable_mp ( this , & EditorFeatureProfileManager : : _profile_action ) . bind ( PROFILE_EXPORT ) ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
main_vbc - > add_child ( current_profile_hbc ) ;
2019-04-09 00:18:03 +02:00
h_split = memnew ( HSplitContainer ) ;
2020-03-06 18:00:16 +01:00
h_split - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2019-04-09 00:18:03 +02:00
main_vbc - > add_child ( h_split ) ;
2020-03-22 21:52:06 +01:00
class_list_vbc = memnew ( VBoxContainer ) ;
2019-04-09 00:18:03 +02:00
h_split - > add_child ( class_list_vbc ) ;
2020-03-06 18:00:16 +01:00
class_list_vbc - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2019-04-09 00:18:03 +02:00
class_list = memnew ( Tree ) ;
2021-07-31 19:08:07 +02:00
class_list_vbc - > add_margin_child ( TTR ( " Configure Selected Profile: " ) , class_list , true ) ;
2019-04-09 00:18:03 +02:00
class_list - > set_hide_root ( true ) ;
class_list - > set_edit_checkbox_cell_only_when_checkbox_is_pressed ( true ) ;
2020-02-21 18:28:45 +01:00
class_list - > connect ( " cell_selected " , callable_mp ( this , & EditorFeatureProfileManager : : _class_list_item_selected ) ) ;
2022-07-28 22:56:41 +02:00
class_list - > connect ( " item_edited " , callable_mp ( this , & EditorFeatureProfileManager : : _class_list_item_edited ) , CONNECT_DEFERRED ) ;
2021-05-27 16:19:33 +02:00
class_list - > connect ( " item_collapsed " , callable_mp ( this , & EditorFeatureProfileManager : : _class_list_item_collapsed ) ) ;
2020-03-22 21:52:06 +01:00
// It will be displayed once the user creates or chooses a profile.
class_list_vbc - > hide ( ) ;
2019-04-09 00:18:03 +02:00
2020-03-22 21:52:06 +01:00
property_list_vbc = memnew ( VBoxContainer ) ;
2019-04-09 00:18:03 +02:00
h_split - > add_child ( property_list_vbc ) ;
2020-03-06 18:00:16 +01:00
property_list_vbc - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2019-04-09 00:18:03 +02:00
2021-05-06 21:24:41 +02:00
description_bit = memnew ( EditorHelpBit ) ;
2021-07-31 19:08:07 +02:00
property_list_vbc - > add_margin_child ( TTR ( " Description: " ) , description_bit , false ) ;
2021-05-06 21:24:41 +02:00
description_bit - > set_custom_minimum_size ( Size2 ( 0 , 80 ) * EDSCALE ) ;
2019-04-09 00:18:03 +02:00
property_list = memnew ( Tree ) ;
2021-07-31 19:08:07 +02:00
property_list_vbc - > add_margin_child ( TTR ( " Extra Options: " ) , property_list , true ) ;
2019-04-09 00:18:03 +02:00
property_list - > set_hide_root ( true ) ;
property_list - > set_hide_folding ( true ) ;
property_list - > set_edit_checkbox_cell_only_when_checkbox_is_pressed ( true ) ;
2022-07-28 22:56:41 +02:00
property_list - > connect ( " item_edited " , callable_mp ( this , & EditorFeatureProfileManager : : _property_item_edited ) , CONNECT_DEFERRED ) ;
2020-03-22 21:52:06 +01:00
// It will be displayed once the user creates or chooses a profile.
property_list_vbc - > hide ( ) ;
no_profile_selected_help = memnew ( Label ( TTR ( " Create or import a profile to edit available classes and properties. " ) ) ) ;
// Add some spacing above the help label.
Ref < StyleBoxEmpty > sb = memnew ( StyleBoxEmpty ) ;
2023-01-19 17:14:09 +01:00
sb - > set_content_margin ( SIDE_TOP , 20 * EDSCALE ) ;
2022-02-08 10:14:58 +01:00
no_profile_selected_help - > add_theme_style_override ( " normal " , sb ) ;
2021-11-25 03:58:47 +01:00
no_profile_selected_help - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2020-05-25 13:10:28 +02:00
no_profile_selected_help - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2020-03-22 21:52:06 +01:00
h_split - > add_child ( no_profile_selected_help ) ;
2019-04-09 00:18:03 +02:00
new_profile_dialog = memnew ( ConfirmationDialog ) ;
2021-05-06 21:24:41 +02:00
new_profile_dialog - > set_title ( TTR ( " Create Profile " ) ) ;
VBoxContainer * new_profile_vb = memnew ( VBoxContainer ) ;
new_profile_dialog - > add_child ( new_profile_vb ) ;
Label * new_profile_label = memnew ( Label ) ;
2021-07-31 19:08:07 +02:00
new_profile_label - > set_text ( TTR ( " New profile name: " ) ) ;
2021-05-06 21:24:41 +02:00
new_profile_vb - > add_child ( new_profile_label ) ;
2019-04-09 00:18:03 +02:00
new_profile_name = memnew ( LineEdit ) ;
2021-05-06 21:24:41 +02:00
new_profile_vb - > add_child ( new_profile_name ) ;
2019-04-09 00:18:03 +02:00
new_profile_name - > set_custom_minimum_size ( Size2 ( 300 * EDSCALE , 1 ) ) ;
add_child ( new_profile_dialog ) ;
2020-02-21 18:28:45 +01:00
new_profile_dialog - > connect ( " confirmed " , callable_mp ( this , & EditorFeatureProfileManager : : _create_new_profile ) ) ;
2019-04-09 00:18:03 +02:00
new_profile_dialog - > register_text_enter ( new_profile_name ) ;
2022-07-08 02:31:19 +02:00
new_profile_dialog - > set_ok_button_text ( TTR ( " Create " ) ) ;
2019-04-09 00:18:03 +02:00
erase_profile_dialog = memnew ( ConfirmationDialog ) ;
add_child ( erase_profile_dialog ) ;
2021-05-06 21:24:41 +02:00
erase_profile_dialog - > set_title ( TTR ( " Remove Profile " ) ) ;
2020-02-21 18:28:45 +01:00
erase_profile_dialog - > connect ( " confirmed " , callable_mp ( this , & EditorFeatureProfileManager : : _erase_selected_profile ) ) ;
2019-04-09 00:18:03 +02:00
import_profiles = memnew ( EditorFileDialog ) ;
add_child ( import_profiles ) ;
2020-03-06 18:00:16 +01:00
import_profiles - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILES ) ;
2022-07-04 23:26:26 +02:00
import_profiles - > add_filter ( " *.profile " , TTR ( " Godot Feature Profile " ) ) ;
2020-02-21 18:28:45 +01:00
import_profiles - > connect ( " files_selected " , callable_mp ( this , & EditorFeatureProfileManager : : _import_profiles ) ) ;
2019-04-09 00:18:03 +02:00
import_profiles - > set_title ( TTR ( " Import Profile(s) " ) ) ;
import_profiles - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
export_profile = memnew ( EditorFileDialog ) ;
add_child ( export_profile ) ;
2020-03-06 18:00:16 +01:00
export_profile - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
2022-07-04 23:26:26 +02:00
export_profile - > add_filter ( " *.profile " , TTR ( " Godot Feature Profile " ) ) ;
2020-02-21 18:28:45 +01:00
export_profile - > connect ( " file_selected " , callable_mp ( this , & EditorFeatureProfileManager : : _export_profile ) ) ;
2019-04-09 00:18:03 +02:00
export_profile - > set_title ( TTR ( " Export Profile " ) ) ;
export_profile - > set_access ( EditorFileDialog : : ACCESS_FILESYSTEM ) ;
set_title ( TTR ( " Manage Editor Feature Profiles " ) ) ;
EDITOR_DEF ( " _default_feature_profile " , " " ) ;
update_timer = memnew ( Timer ) ;
update_timer - > set_wait_time ( 1 ) ; //wait a second before updating editor
add_child ( update_timer ) ;
2020-02-21 18:28:45 +01:00
update_timer - > connect ( " timeout " , callable_mp ( this , & EditorFeatureProfileManager : : _emit_current_profile_changed ) ) ;
2019-04-09 00:18:03 +02:00
update_timer - > set_one_shot ( true ) ;
singleton = this ;
}