2021-06-04 11:24:08 +02:00
/**************************************************************************/
/* shader_create_dialog.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
# include "shader_create_dialog.h"
2022-02-12 02:46:22 +01:00
# include "core/config/project_settings.h"
2023-04-07 18:59:49 +02:00
# include "editor/gui/editor_file_dialog.h"
2023-06-26 19:18:27 +02:00
# include "editor/gui/editor_validation_panel.h"
2024-01-15 13:14:55 +01:00
# include "editor/themes/editor_scale.h"
2022-03-08 11:39:16 +01:00
# include "scene/resources/shader_include.h"
2021-06-04 11:24:08 +02:00
# include "scene/resources/visual_shader.h"
# include "servers/rendering/shader_types.h"
2022-08-15 22:08:50 +02:00
enum ShaderType {
SHADER_TYPE_TEXT ,
SHADER_TYPE_VISUAL ,
SHADER_TYPE_INC ,
SHADER_TYPE_MAX ,
} ;
2021-06-04 11:24:08 +02:00
void ShaderCreateDialog : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE : {
String last_lang = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " shader_setup " , " last_selected_language " , " " ) ;
if ( ! last_lang . is_empty ( ) ) {
2022-03-08 11:39:16 +01:00
for ( int i = 0 ; i < type_menu - > get_item_count ( ) ; i + + ) {
if ( type_menu - > get_item_text ( i ) = = last_lang ) {
type_menu - > select ( i ) ;
current_type = i ;
2021-06-04 11:24:08 +02:00
break ;
}
}
} else {
2022-03-08 11:39:16 +01:00
type_menu - > select ( default_type ) ;
2021-06-04 11:24:08 +02:00
}
current_mode = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " shader_setup " , " last_selected_mode " , 0 ) ;
mode_menu - > select ( current_mode ) ;
} break ;
2022-02-16 15:17:55 +01:00
2021-06-04 11:24:08 +02:00
case NOTIFICATION_THEME_CHANGED : {
2023-12-04 13:18:48 +01:00
static const char * shader_types [ 3 ] = { " Shader " , " VisualShader " , " TextFile " } ;
for ( int i = 0 ; i < 3 ; i + + ) {
Ref < Texture2D > icon = get_editor_theme_icon ( shader_types [ i ] ) ;
if ( icon . is_valid ( ) ) {
type_menu - > set_item_icon ( i , icon ) ;
}
}
2022-03-08 11:39:16 +01:00
2023-12-04 13:18:48 +01:00
path_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Folder " ) ) ) ;
} break ;
2021-06-04 11:24:08 +02:00
}
}
void ShaderCreateDialog : : _update_language_info ( ) {
2022-03-08 11:39:16 +01:00
type_data . clear ( ) ;
2021-06-04 11:24:08 +02:00
2021-08-09 09:41:01 +02:00
for ( int i = 0 ; i < SHADER_TYPE_MAX ; i + + ) {
2022-09-29 11:53:28 +02:00
ShaderTypeData shader_type_data ;
2021-08-09 09:41:01 +02:00
if ( i = = int ( SHADER_TYPE_TEXT ) ) {
2022-09-29 11:53:28 +02:00
shader_type_data . use_templates = true ;
shader_type_data . extensions . push_back ( " gdshader " ) ;
shader_type_data . default_extension = " gdshader " ;
2022-03-08 11:39:16 +01:00
} else if ( i = = int ( SHADER_TYPE_INC ) ) {
2022-09-29 11:53:28 +02:00
shader_type_data . extensions . push_back ( " gdshaderinc " ) ;
shader_type_data . default_extension = " gdshaderinc " ;
2021-06-04 11:24:08 +02:00
} else {
2022-09-29 11:53:28 +02:00
shader_type_data . default_extension = " tres " ;
2021-06-04 11:24:08 +02:00
}
2022-09-29 11:53:28 +02:00
shader_type_data . extensions . push_back ( " res " ) ;
shader_type_data . extensions . push_back ( " tres " ) ;
type_data . push_back ( shader_type_data ) ;
2021-06-04 11:24:08 +02:00
}
}
void ShaderCreateDialog : : _path_hbox_sorted ( ) {
if ( is_visible ( ) ) {
int filename_start_pos = initial_base_path . rfind ( " / " ) + 1 ;
int filename_end_pos = initial_base_path . length ( ) ;
if ( ! is_built_in ) {
file_path - > select ( filename_start_pos , filename_end_pos ) ;
}
file_path - > set_caret_column ( file_path - > get_text ( ) . length ( ) ) ;
file_path - > set_caret_column ( filename_start_pos ) ;
file_path - > grab_focus ( ) ;
}
}
void ShaderCreateDialog : : _mode_changed ( int p_mode ) {
current_mode = p_mode ;
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " shader_setup " , " last_selected_mode " , p_mode ) ;
}
void ShaderCreateDialog : : _template_changed ( int p_template ) {
current_template = p_template ;
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " shader_setup " , " last_selected_template " , p_template ) ;
}
void ShaderCreateDialog : : ok_pressed ( ) {
if ( is_new_shader_created ) {
_create_new ( ) ;
} else {
_load_exist ( ) ;
}
is_new_shader_created = true ;
2023-06-26 19:18:27 +02:00
validation_panel - > update ( ) ;
2021-06-04 11:24:08 +02:00
}
void ShaderCreateDialog : : _create_new ( ) {
2022-05-03 01:43:50 +02:00
Ref < Resource > shader ;
2022-03-08 11:39:16 +01:00
Ref < Resource > shader_inc ;
switch ( type_menu - > get_selected ( ) ) {
case SHADER_TYPE_TEXT : {
Ref < Shader > text_shader ;
text_shader . instantiate ( ) ;
shader = text_shader ;
StringBuilder code ;
2022-08-30 11:36:24 +02:00
code + = vformat ( " shader_type %s; \n " , mode_menu - > get_text ( ) . to_snake_case ( ) ) ;
2022-03-08 11:39:16 +01:00
if ( current_template = = 0 ) { // Default template.
switch ( current_mode ) {
case Shader : : MODE_SPATIAL :
2021-08-18 23:54:24 +02:00
code + = R " (
void vertex ( ) {
// Called for every vertex the material is visible on.
}
void fragment ( ) {
// Called for every pixel the material is visible on.
}
2023-11-07 23:20:45 +01:00
//void light() {
2021-08-18 23:54:24 +02:00
// Called for every pixel for every light affecting the material.
2023-11-07 23:20:45 +01:00
// Uncomment to replace the default light processing function with this one.
//}
2021-08-18 23:54:24 +02:00
) " ;
2022-03-08 11:39:16 +01:00
break ;
case Shader : : MODE_CANVAS_ITEM :
2021-08-18 23:54:24 +02:00
code + = R " (
void vertex ( ) {
// Called for every vertex the material is visible on.
}
void fragment ( ) {
// Called for every pixel the material is visible on.
}
2023-11-07 23:20:45 +01:00
//void light() {
2021-08-18 23:54:24 +02:00
// Called for every pixel for every light affecting the CanvasItem.
2023-11-07 23:20:45 +01:00
// Uncomment to replace the default light processing function with this one.
//}
2021-08-18 23:54:24 +02:00
) " ;
2022-03-08 11:39:16 +01:00
break ;
case Shader : : MODE_PARTICLES :
2021-08-18 23:54:24 +02:00
code + = R " (
void start ( ) {
// Called when a particle is spawned.
}
void process ( ) {
// Called every frame on existing particles (according to the Fixed FPS property).
}
) " ;
2022-03-08 11:39:16 +01:00
break ;
case Shader : : MODE_SKY :
2021-08-18 23:54:24 +02:00
code + = R " (
void sky ( ) {
// Called for every visible pixel in the sky background, as well as all pixels
// in the radiance cubemap.
}
) " ;
2022-03-08 11:39:16 +01:00
break ;
case Shader : : MODE_FOG :
2021-08-18 23:54:24 +02:00
code + = R " (
void fog ( ) {
// Called once for every froxel that is touched by an axis-aligned bounding box
// of the associated FogVolume. This means that froxels that just barely touch
// a given FogVolume will still be used.
}
) " ;
2022-03-08 11:39:16 +01:00
}
2021-06-04 11:24:08 +02:00
}
2022-03-08 11:39:16 +01:00
text_shader - > set_code ( code . as_string ( ) ) ;
} break ;
case SHADER_TYPE_VISUAL : {
Ref < VisualShader > visual_shader ;
visual_shader . instantiate ( ) ;
shader = visual_shader ;
visual_shader - > set_mode ( Shader : : Mode ( current_mode ) ) ;
} break ;
case SHADER_TYPE_INC : {
Ref < ShaderInclude > include ;
include . instantiate ( ) ;
shader_inc = include ;
} break ;
default : {
} break ;
2021-06-04 11:24:08 +02:00
}
2022-03-08 11:39:16 +01:00
if ( shader . is_null ( ) ) {
2021-06-04 11:24:08 +02:00
String lpath = ProjectSettings : : get_singleton ( ) - > localize_path ( file_path - > get_text ( ) ) ;
2022-03-08 11:39:16 +01:00
shader_inc - > set_path ( lpath ) ;
2022-06-03 01:33:42 +02:00
Error error = ResourceSaver : : save ( shader_inc , lpath , ResourceSaver : : FLAG_CHANGE_PATH ) ;
2022-03-08 11:39:16 +01:00
if ( error ! = OK ) {
alert - > set_text ( TTR ( " Error - Could not create shader include in filesystem. " ) ) ;
2021-06-04 11:24:08 +02:00
alert - > popup_centered ( ) ;
return ;
}
2022-03-08 11:39:16 +01:00
emit_signal ( SNAME ( " shader_include_created " ) , shader_inc ) ;
} else {
2023-12-31 16:20:38 +01:00
if ( is_built_in ) {
Node * edited_scene = get_tree ( ) - > get_edited_scene_root ( ) ;
if ( likely ( edited_scene ) ) {
shader - > set_path ( edited_scene - > get_scene_file_path ( ) + " :: " ) ;
}
} else {
2022-03-08 11:39:16 +01:00
String lpath = ProjectSettings : : get_singleton ( ) - > localize_path ( file_path - > get_text ( ) ) ;
shader - > set_path ( lpath ) ;
2022-06-03 01:33:42 +02:00
Error error = ResourceSaver : : save ( shader , lpath , ResourceSaver : : FLAG_CHANGE_PATH ) ;
2022-03-08 11:39:16 +01:00
if ( error ! = OK ) {
alert - > set_text ( TTR ( " Error - Could not create shader in filesystem. " ) ) ;
alert - > popup_centered ( ) ;
return ;
}
}
emit_signal ( SNAME ( " shader_created " ) , shader ) ;
2021-06-04 11:24:08 +02:00
}
2022-03-08 11:39:16 +01:00
file_path - > set_text ( file_path - > get_text ( ) . get_base_dir ( ) ) ;
2021-06-04 11:24:08 +02:00
hide ( ) ;
}
void ShaderCreateDialog : : _load_exist ( ) {
String path = file_path - > get_text ( ) ;
2022-05-03 01:43:50 +02:00
Ref < Resource > p_shader = ResourceLoader : : load ( path , " Shader " ) ;
2021-06-04 11:24:08 +02:00
if ( p_shader . is_null ( ) ) {
alert - > set_text ( vformat ( TTR ( " Error loading shader from %s " ) , path ) ) ;
alert - > popup_centered ( ) ;
return ;
}
2021-08-20 14:48:34 +02:00
emit_signal ( SNAME ( " shader_created " ) , p_shader ) ;
2021-06-04 11:24:08 +02:00
hide ( ) ;
}
2022-03-08 11:39:16 +01:00
void ShaderCreateDialog : : _type_changed ( int p_language ) {
current_type = p_language ;
2024-04-15 15:18:34 +02:00
ShaderTypeData shader_type_data = type_data . get ( p_language ) ;
2021-06-04 11:24:08 +02:00
2022-09-29 11:53:28 +02:00
String selected_ext = " . " + shader_type_data . default_extension ;
2021-06-04 11:24:08 +02:00
String path = file_path - > get_text ( ) ;
String extension = " " ;
2021-12-09 10:42:46 +01:00
if ( ! path . is_empty ( ) ) {
2022-02-03 17:03:38 +01:00
if ( path . contains ( " . " ) ) {
2021-06-04 11:24:08 +02:00
extension = path . get_extension ( ) ;
}
if ( extension . length ( ) = = 0 ) {
path + = selected_ext ;
} else {
path = path . get_basename ( ) + selected_ext ;
}
} else {
path = " shader " + selected_ext ;
}
_path_changed ( path ) ;
file_path - > set_text ( path ) ;
2022-03-08 11:39:16 +01:00
type_menu - > set_item_disabled ( int ( SHADER_TYPE_INC ) , load_enabled ) ;
mode_menu - > set_disabled ( p_language = = SHADER_TYPE_INC ) ;
2022-09-29 11:53:28 +02:00
template_menu - > set_disabled ( ! shader_type_data . use_templates ) ;
2021-06-04 11:24:08 +02:00
template_menu - > clear ( ) ;
2022-09-29 11:53:28 +02:00
if ( shader_type_data . use_templates ) {
2021-06-04 11:24:08 +02:00
int last_template = EditorSettings : : get_singleton ( ) - > get_project_metadata ( " shader_setup " , " last_selected_template " , 0 ) ;
template_menu - > add_item ( TTR ( " Default " ) ) ;
template_menu - > add_item ( TTR ( " Empty " ) ) ;
template_menu - > select ( last_template ) ;
current_template = last_template ;
} else {
template_menu - > add_item ( TTR ( " N/A " ) ) ;
}
2022-03-08 11:39:16 +01:00
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " shader_setup " , " last_selected_language " , type_menu - > get_item_text ( type_menu - > get_selected ( ) ) ) ;
2023-06-26 19:18:27 +02:00
validation_panel - > update ( ) ;
2021-06-04 11:24:08 +02:00
}
void ShaderCreateDialog : : _built_in_toggled ( bool p_enabled ) {
is_built_in = p_enabled ;
if ( p_enabled ) {
is_new_shader_created = true ;
} else {
_path_changed ( file_path - > get_text ( ) ) ;
}
2023-06-26 19:18:27 +02:00
validation_panel - > update ( ) ;
2021-06-04 11:24:08 +02:00
}
void ShaderCreateDialog : : _browse_path ( ) {
file_browse - > set_file_mode ( EditorFileDialog : : FILE_MODE_SAVE_FILE ) ;
file_browse - > set_title ( TTR ( " Open Shader / Choose Location " ) ) ;
2022-07-08 02:31:19 +02:00
file_browse - > set_ok_button_text ( TTR ( " Open " ) ) ;
2021-06-04 11:24:08 +02:00
file_browse - > set_disable_overwrite_warning ( true ) ;
file_browse - > clear_filters ( ) ;
2024-04-15 15:18:34 +02:00
List < String > extensions = type_data . get ( type_menu - > get_selected ( ) ) . extensions ;
2021-06-04 11:24:08 +02:00
for ( const String & E : extensions ) {
file_browse - > add_filter ( " *. " + E ) ;
}
file_browse - > set_current_path ( file_path - > get_text ( ) ) ;
file_browse - > popup_file_dialog ( ) ;
}
void ShaderCreateDialog : : _file_selected ( const String & p_file ) {
String p = ProjectSettings : : get_singleton ( ) - > localize_path ( p_file ) ;
file_path - > set_text ( p ) ;
_path_changed ( p ) ;
String filename = p . get_file ( ) . get_basename ( ) ;
int select_start = p . rfind ( filename ) ;
file_path - > select ( select_start , select_start + filename . length ( ) ) ;
file_path - > set_caret_column ( select_start + filename . length ( ) ) ;
file_path - > grab_focus ( ) ;
}
void ShaderCreateDialog : : _path_changed ( const String & p_path ) {
if ( is_built_in ) {
return ;
}
is_path_valid = false ;
is_new_shader_created = true ;
2023-06-26 19:18:27 +02:00
path_error = _validate_path ( p_path ) ;
2021-12-09 10:42:46 +01:00
if ( ! path_error . is_empty ( ) ) {
2023-06-26 19:18:27 +02:00
validation_panel - > update ( ) ;
2021-06-04 11:24:08 +02:00
return ;
}
2022-03-23 10:08:58 +01:00
Ref < DirAccess > f = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2021-06-04 11:24:08 +02:00
String p = ProjectSettings : : get_singleton ( ) - > localize_path ( p_path . strip_edges ( ) ) ;
if ( f - > file_exists ( p ) ) {
is_new_shader_created = false ;
}
is_path_valid = true ;
2023-06-26 19:18:27 +02:00
validation_panel - > update ( ) ;
2021-06-04 11:24:08 +02:00
}
void ShaderCreateDialog : : _path_submitted ( const String & p_path ) {
2023-06-26 19:18:27 +02:00
if ( ! get_ok_button ( ) - > is_disabled ( ) ) {
ok_pressed ( ) ;
}
2021-06-04 11:24:08 +02:00
}
2021-12-03 15:45:32 +01:00
void ShaderCreateDialog : : config ( const String & p_base_path , bool p_built_in_enabled , bool p_load_enabled , int p_preferred_type , int p_preferred_mode ) {
2021-12-09 10:42:46 +01:00
if ( ! p_base_path . is_empty ( ) ) {
2021-06-04 11:24:08 +02:00
initial_base_path = p_base_path . get_basename ( ) ;
2024-04-15 15:18:34 +02:00
file_path - > set_text ( initial_base_path + " . " + type_data . get ( type_menu - > get_selected ( ) ) . default_extension ) ;
2022-03-08 11:39:16 +01:00
current_type = type_menu - > get_selected ( ) ;
2021-06-04 11:24:08 +02:00
} else {
initial_base_path = " " ;
file_path - > set_text ( " " ) ;
}
file_path - > deselect ( ) ;
built_in_enabled = p_built_in_enabled ;
load_enabled = p_load_enabled ;
2021-12-03 15:45:32 +01:00
if ( p_preferred_type > - 1 ) {
2022-03-08 11:39:16 +01:00
type_menu - > select ( p_preferred_type ) ;
_type_changed ( p_preferred_type ) ;
2021-12-03 15:45:32 +01:00
}
2021-09-17 16:35:24 +02:00
if ( p_preferred_mode > - 1 ) {
mode_menu - > select ( p_preferred_mode ) ;
_mode_changed ( p_preferred_mode ) ;
}
2022-03-08 11:39:16 +01:00
_type_changed ( current_type ) ;
2021-06-04 11:24:08 +02:00
_path_changed ( file_path - > get_text ( ) ) ;
}
2021-08-09 09:41:01 +02:00
String ShaderCreateDialog : : _validate_path ( const String & p_path ) {
2021-06-04 11:24:08 +02:00
String p = p_path . strip_edges ( ) ;
2021-12-09 10:42:46 +01:00
if ( p . is_empty ( ) ) {
2021-06-04 11:24:08 +02:00
return TTR ( " Path is empty. " ) ;
}
2021-12-09 10:42:46 +01:00
if ( p . get_file ( ) . get_basename ( ) . is_empty ( ) ) {
2021-06-04 11:24:08 +02:00
return TTR ( " Filename is empty. " ) ;
}
p = ProjectSettings : : get_singleton ( ) - > localize_path ( p ) ;
if ( ! p . begins_with ( " res:// " ) ) {
return TTR ( " Path is not local. " ) ;
}
2022-03-23 10:08:58 +01:00
Ref < DirAccess > d = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2021-06-04 11:24:08 +02:00
if ( d - > change_dir ( p . get_base_dir ( ) ) ! = OK ) {
return TTR ( " Invalid base path. " ) ;
}
2022-03-23 10:08:58 +01:00
Ref < DirAccess > f = DirAccess : : create ( DirAccess : : ACCESS_RESOURCES ) ;
2021-06-04 11:24:08 +02:00
if ( f - > dir_exists ( p ) ) {
return TTR ( " A directory with the same name exists. " ) ;
}
String extension = p . get_extension ( ) ;
2022-05-19 17:00:06 +02:00
HashSet < String > extensions ;
2021-06-04 11:24:08 +02:00
2024-04-15 15:18:34 +02:00
List < ShaderCreateDialog : : ShaderTypeData > : : ConstIterator itr = type_data . begin ( ) ;
for ( int i = 0 ; i < SHADER_TYPE_MAX ; + + itr , + + i ) {
for ( const String & ext : itr - > extensions ) {
2021-08-09 09:41:01 +02:00
if ( ! extensions . has ( ext ) ) {
extensions . insert ( ext ) ;
2021-08-09 08:32:16 +02:00
}
2021-06-04 11:24:08 +02:00
}
}
2021-08-09 09:41:01 +02:00
bool found = false ;
2021-06-04 11:24:08 +02:00
bool match = false ;
2021-08-09 09:41:01 +02:00
for ( const String & ext : extensions ) {
if ( ext . nocasecmp_to ( extension ) = = 0 ) {
found = true ;
2024-04-15 15:18:34 +02:00
for ( const String & type_ext : type_data . get ( current_type ) . extensions ) {
2022-03-08 11:39:16 +01:00
if ( type_ext . nocasecmp_to ( extension ) = = 0 ) {
2021-08-09 09:41:01 +02:00
match = true ;
break ;
}
}
2021-06-04 11:24:08 +02:00
break ;
}
}
2021-08-09 09:41:01 +02:00
if ( ! found ) {
return TTR ( " Invalid extension. " ) ;
}
2021-06-04 11:24:08 +02:00
if ( ! match ) {
return TTR ( " Wrong extension chosen. " ) ;
}
return " " ;
}
void ShaderCreateDialog : : _update_dialog ( ) {
if ( ! is_built_in & & ! is_path_valid ) {
2023-06-26 19:18:27 +02:00
validation_panel - > set_message ( MSG_ID_SHADER , TTR ( " Invalid path. " ) , EditorValidationPanel : : MSG_ERROR ) ;
2021-06-04 11:24:08 +02:00
}
2023-10-27 21:49:34 +02:00
if ( ! is_built_in & & ! path_error . is_empty ( ) ) {
2023-06-26 19:18:27 +02:00
validation_panel - > set_message ( MSG_ID_PATH , path_error , EditorValidationPanel : : MSG_ERROR ) ;
} else if ( validation_panel - > is_valid ( ) & & ! is_new_shader_created ) {
validation_panel - > set_message ( MSG_ID_SHADER , TTR ( " File exists, it will be reused. " ) , EditorValidationPanel : : MSG_OK ) ;
2021-06-04 11:24:08 +02:00
}
if ( ! built_in_enabled ) {
internal - > set_pressed ( false ) ;
}
if ( is_built_in ) {
file_path - > set_editable ( false ) ;
path_button - > set_disabled ( true ) ;
re_check_path = true ;
} else {
file_path - > set_editable ( true ) ;
path_button - > set_disabled ( false ) ;
if ( re_check_path ) {
re_check_path = false ;
_path_changed ( file_path - > get_text ( ) ) ;
}
}
internal - > set_disabled ( ! built_in_enabled ) ;
2023-06-26 19:18:27 +02:00
if ( is_built_in ) {
validation_panel - > set_message ( MSG_ID_BUILT_IN , TTR ( " Note: Built-in shaders can't be edited using an external editor. " ) , EditorValidationPanel : : MSG_INFO , false ) ;
}
2021-06-04 11:24:08 +02:00
if ( is_built_in ) {
2022-07-08 02:31:19 +02:00
set_ok_button_text ( TTR ( " Create " ) ) ;
2023-06-26 19:18:27 +02:00
validation_panel - > set_message ( MSG_ID_PATH , TTR ( " Built-in shader (into scene file). " ) , EditorValidationPanel : : MSG_OK ) ;
2021-06-04 11:24:08 +02:00
} else if ( is_new_shader_created ) {
2022-07-08 02:31:19 +02:00
set_ok_button_text ( TTR ( " Create " ) ) ;
2021-06-04 11:24:08 +02:00
} else if ( load_enabled ) {
2022-07-08 02:31:19 +02:00
set_ok_button_text ( TTR ( " Load " ) ) ;
2021-06-04 11:24:08 +02:00
if ( is_path_valid ) {
2023-06-26 19:18:27 +02:00
validation_panel - > set_message ( MSG_ID_PATH , TTR ( " Will load an existing shader file. " ) , EditorValidationPanel : : MSG_OK ) ;
2021-06-04 11:24:08 +02:00
}
} else {
2022-07-08 02:31:19 +02:00
set_ok_button_text ( TTR ( " Create " ) ) ;
2023-06-26 19:18:27 +02:00
validation_panel - > set_message ( MSG_ID_PATH , TTR ( " Shader file already exists. " ) , EditorValidationPanel : : MSG_ERROR ) ;
2021-06-04 11:24:08 +02:00
}
}
void ShaderCreateDialog : : _bind_methods ( ) {
ClassDB : : bind_method ( D_METHOD ( " config " , " path " , " built_in_enabled " , " load_enabled " ) , & ShaderCreateDialog : : config , DEFVAL ( true ) , DEFVAL ( true ) ) ;
ADD_SIGNAL ( MethodInfo ( " shader_created " , PropertyInfo ( Variant : : OBJECT , " shader " , PROPERTY_HINT_RESOURCE_TYPE , " Shader " ) ) ) ;
2022-03-08 11:39:16 +01:00
ADD_SIGNAL ( MethodInfo ( " shader_include_created " , PropertyInfo ( Variant : : OBJECT , " shader_include " , PROPERTY_HINT_RESOURCE_TYPE , " ShaderInclude " ) ) ) ;
2021-06-04 11:24:08 +02:00
}
ShaderCreateDialog : : ShaderCreateDialog ( ) {
_update_language_info ( ) ;
// Main Controls.
gc = memnew ( GridContainer ) ;
gc - > set_columns ( 2 ) ;
// Error Fields.
2023-06-26 19:18:27 +02:00
validation_panel = memnew ( EditorValidationPanel ) ;
validation_panel - > add_line ( MSG_ID_SHADER , TTR ( " Shader path/name is valid. " ) ) ;
validation_panel - > add_line ( MSG_ID_PATH , TTR ( " Will create a new shader file. " ) ) ;
validation_panel - > add_line ( MSG_ID_BUILT_IN ) ;
validation_panel - > set_update_callback ( callable_mp ( this , & ShaderCreateDialog : : _update_dialog ) ) ;
validation_panel - > set_accept_button ( get_ok_button ( ) ) ;
2021-06-04 11:24:08 +02:00
// Spacing.
Control * spacing = memnew ( Control ) ;
spacing - > set_custom_minimum_size ( Size2 ( 0 , 10 * EDSCALE ) ) ;
2023-06-26 19:18:27 +02:00
VBoxContainer * vb = memnew ( VBoxContainer ) ;
2021-06-04 11:24:08 +02:00
vb - > add_child ( gc ) ;
vb - > add_child ( spacing ) ;
2023-06-26 19:18:27 +02:00
vb - > add_child ( validation_panel ) ;
2021-06-04 11:24:08 +02:00
add_child ( vb ) ;
2022-03-08 11:39:16 +01:00
// Type.
2021-06-04 11:24:08 +02:00
2022-03-08 11:39:16 +01:00
type_menu = memnew ( OptionButton ) ;
type_menu - > set_custom_minimum_size ( Size2 ( 250 , 0 ) * EDSCALE ) ;
type_menu - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
gc - > add_child ( memnew ( Label ( TTR ( " Type: " ) ) ) ) ;
gc - > add_child ( type_menu ) ;
2021-06-04 11:24:08 +02:00
for ( int i = 0 ; i < SHADER_TYPE_MAX ; i + + ) {
2022-03-08 11:39:16 +01:00
String type ;
2021-06-04 11:24:08 +02:00
bool invalid = false ;
switch ( i ) {
case SHADER_TYPE_TEXT :
2022-03-08 11:39:16 +01:00
type = " Shader " ;
default_type = i ;
2021-06-04 11:24:08 +02:00
break ;
case SHADER_TYPE_VISUAL :
2022-03-08 11:39:16 +01:00
type = " VisualShader " ;
break ;
case SHADER_TYPE_INC :
type = " ShaderInclude " ;
2021-06-04 11:24:08 +02:00
break ;
case SHADER_TYPE_MAX :
invalid = true ;
break ;
default :
invalid = true ;
break ;
}
if ( invalid ) {
continue ;
}
2022-03-08 11:39:16 +01:00
type_menu - > add_item ( type ) ;
2021-06-04 11:24:08 +02:00
}
2022-03-08 11:39:16 +01:00
if ( default_type > = 0 ) {
type_menu - > select ( default_type ) ;
2021-06-04 11:24:08 +02:00
}
2022-03-08 11:39:16 +01:00
current_type = default_type ;
2024-05-14 14:21:31 +02:00
type_menu - > connect ( SceneStringName ( item_selected ) , callable_mp ( this , & ShaderCreateDialog : : _type_changed ) ) ;
2021-06-04 11:24:08 +02:00
// Modes.
mode_menu = memnew ( OptionButton ) ;
2021-08-09 09:41:01 +02:00
for ( const String & type_name : ShaderTypes : : get_singleton ( ) - > get_types_list ( ) ) {
mode_menu - > add_item ( type_name . capitalize ( ) ) ;
2021-06-04 11:24:08 +02:00
}
gc - > add_child ( memnew ( Label ( TTR ( " Mode: " ) ) ) ) ;
gc - > add_child ( mode_menu ) ;
2024-05-14 14:21:31 +02:00
mode_menu - > connect ( SceneStringName ( item_selected ) , callable_mp ( this , & ShaderCreateDialog : : _mode_changed ) ) ;
2021-06-04 11:24:08 +02:00
// Templates.
template_menu = memnew ( OptionButton ) ;
gc - > add_child ( memnew ( Label ( TTR ( " Template: " ) ) ) ) ;
gc - > add_child ( template_menu ) ;
2024-05-14 14:21:31 +02:00
template_menu - > connect ( SceneStringName ( item_selected ) , callable_mp ( this , & ShaderCreateDialog : : _template_changed ) ) ;
2021-06-04 11:24:08 +02:00
// Built-in Shader.
internal = memnew ( CheckBox ) ;
internal - > set_text ( TTR ( " On " ) ) ;
internal - > connect ( " toggled " , callable_mp ( this , & ShaderCreateDialog : : _built_in_toggled ) ) ;
gc - > add_child ( memnew ( Label ( TTR ( " Built-in Shader: " ) ) ) ) ;
gc - > add_child ( internal ) ;
// Path.
HBoxContainer * hb = memnew ( HBoxContainer ) ;
hb - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2024-05-13 16:56:03 +02:00
hb - > connect ( SceneStringName ( sort_children ) , callable_mp ( this , & ShaderCreateDialog : : _path_hbox_sorted ) ) ;
2021-06-04 11:24:08 +02:00
file_path = memnew ( LineEdit ) ;
2024-05-14 11:42:00 +02:00
file_path - > connect ( SceneStringName ( text_changed ) , callable_mp ( this , & ShaderCreateDialog : : _path_changed ) ) ;
2021-06-04 11:24:08 +02:00
file_path - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
hb - > add_child ( file_path ) ;
2023-11-06 17:20:18 +01:00
register_text_enter ( file_path ) ;
2021-06-04 11:24:08 +02:00
path_button = memnew ( Button ) ;
2024-05-14 09:40:21 +02:00
path_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & ShaderCreateDialog : : _browse_path ) ) ;
2021-06-04 11:24:08 +02:00
hb - > add_child ( path_button ) ;
gc - > add_child ( memnew ( Label ( TTR ( " Path: " ) ) ) ) ;
gc - > add_child ( hb ) ;
// Dialog Setup.
file_browse = memnew ( EditorFileDialog ) ;
file_browse - > connect ( " file_selected " , callable_mp ( this , & ShaderCreateDialog : : _file_selected ) ) ;
file_browse - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILE ) ;
add_child ( file_browse ) ;
alert = memnew ( AcceptDialog ) ;
2022-06-15 10:01:45 +02:00
alert - > get_label ( ) - > set_autowrap_mode ( TextServer : : AUTOWRAP_WORD_SMART ) ;
2021-11-25 03:58:47 +01:00
alert - > get_label ( ) - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
alert - > get_label ( ) - > set_vertical_alignment ( VERTICAL_ALIGNMENT_CENTER ) ;
2021-06-04 11:24:08 +02:00
alert - > get_label ( ) - > set_custom_minimum_size ( Size2 ( 325 , 60 ) * EDSCALE ) ;
add_child ( alert ) ;
2022-07-08 02:31:19 +02:00
set_ok_button_text ( TTR ( " Create " ) ) ;
2021-06-04 11:24:08 +02:00
set_hide_on_ok ( false ) ;
set_title ( TTR ( " Create Shader " ) ) ;
}