2021-05-07 13:41:39 +00:00
/**************************************************************************/
/* tile_set_editor.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 "tile_set_editor.h"
# include "tile_data_editors.h"
# include "tiles_editor_plugin.h"
2022-02-14 13:00:03 +00:00
# include "editor/editor_file_system.h"
2023-07-14 16:25:51 +00:00
# include "editor/editor_inspector.h"
2022-02-12 01:46:22 +00:00
# include "editor/editor_node.h"
2022-11-19 11:45:49 +00:00
# include "editor/editor_settings.h"
2022-03-25 17:06:46 +00:00
# include "editor/editor_undo_redo_manager.h"
2023-07-10 13:36:00 +00:00
# include "editor/gui/editor_file_dialog.h"
2024-01-15 12:14:55 +00:00
# include "editor/themes/editor_scale.h"
2021-05-07 13:41:39 +00:00
# include "scene/gui/box_container.h"
# include "scene/gui/control.h"
2023-07-14 16:25:51 +00:00
# include "scene/gui/dialogs.h"
2021-05-07 13:41:39 +00:00
# include "scene/gui/tab_container.h"
TileSetEditor * TileSetEditor : : singleton = nullptr ;
2021-11-01 09:22:41 +00:00
void TileSetEditor : : _drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) {
2021-05-07 13:41:39 +00:00
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
2021-11-01 09:22:41 +00:00
if ( ! _can_drop_data_fw ( p_point , p_data , p_from ) ) {
2021-05-07 13:41:39 +00:00
return ;
}
if ( p_from = = sources_list ) {
// Handle dropping a texture in the list of atlas resources.
Dictionary d = p_data ;
Vector < String > files = d [ " files " ] ;
2023-07-19 13:38:08 +00:00
_load_texture_files ( files ) ;
2021-05-07 13:41:39 +00:00
}
}
2021-11-01 09:22:41 +00:00
bool TileSetEditor : : _can_drop_data_fw ( const Point2 & p_point , const Variant & p_data , Control * p_from ) const {
2021-05-07 13:41:39 +00:00
ERR_FAIL_COND_V ( ! tile_set . is_valid ( ) , false ) ;
2022-09-06 12:26:19 +00:00
if ( read_only ) {
return false ;
}
2021-05-07 13:41:39 +00:00
if ( p_from = = sources_list ) {
Dictionary d = p_data ;
if ( ! d . has ( " type " ) ) {
return false ;
}
// Check if we have a Texture2D.
if ( String ( d [ " type " ] ) = = " files " ) {
Vector < String > files = d [ " files " ] ;
if ( files . size ( ) = = 0 ) {
return false ;
}
for ( int i = 0 ; i < files . size ( ) ; i + + ) {
2023-12-13 16:06:14 +00:00
String ftype = EditorFileSystem : : get_singleton ( ) - > get_file_type ( files [ i ] ) ;
2021-05-07 13:41:39 +00:00
if ( ! ClassDB : : is_parent_class ( ftype , " Texture2D " ) ) {
return false ;
}
}
return true ;
}
}
return false ;
}
2023-07-19 13:38:08 +00:00
void TileSetEditor : : _load_texture_files ( const Vector < String > & p_paths ) {
int source_id = TileSet : : INVALID_SOURCE ;
Vector < Ref < TileSetAtlasSource > > atlases ;
for ( const String & p_path : p_paths ) {
Ref < Texture2D > texture = ResourceLoader : : load ( p_path ) ;
if ( texture . is_null ( ) ) {
EditorNode : : get_singleton ( ) - > show_warning ( TTR ( " Invalid texture selected. " ) ) ;
continue ;
}
// Retrieve the id for the next created source.
source_id = tile_set - > get_next_source_id ( ) ;
// Actually create the new source.
Ref < TileSetAtlasSource > atlas_source = memnew ( TileSetAtlasSource ) ;
atlas_source - > set_texture ( texture ) ;
2023-12-21 09:25:21 +00:00
atlas_source - > set_texture_region_size ( tile_set - > get_tile_size ( ) ) ;
2023-07-19 13:38:08 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
undo_redo - > create_action ( TTR ( " Add a new atlas source " ) ) ;
undo_redo - > add_do_method ( * tile_set , " add_source " , atlas_source , source_id ) ;
undo_redo - > add_undo_method ( * tile_set , " remove_source " , source_id ) ;
undo_redo - > commit_action ( ) ;
atlases . append ( atlas_source ) ;
}
if ( ! atlases . is_empty ( ) ) {
tile_set_atlas_source_editor - > init_new_atlases ( atlases ) ;
}
// Update the selected source (thus triggering an update).
_update_sources_list ( source_id ) ;
}
2021-07-06 12:43:03 +00:00
void TileSetEditor : : _update_sources_list ( int force_selected_id ) {
2022-12-10 05:09:20 +00:00
if ( tile_set . is_null ( ) ) {
return ;
}
2021-05-07 13:41:39 +00:00
// Get the previously selected id.
2021-07-06 12:43:03 +00:00
int old_selected = TileSet : : INVALID_SOURCE ;
2021-05-07 13:41:39 +00:00
if ( sources_list - > get_current ( ) > = 0 ) {
int source_id = sources_list - > get_item_metadata ( sources_list - > get_current ( ) ) ;
if ( tile_set - > has_source ( source_id ) ) {
old_selected = source_id ;
}
}
2021-07-06 12:43:03 +00:00
int to_select = TileSet : : INVALID_SOURCE ;
2021-05-07 13:41:39 +00:00
if ( force_selected_id > = 0 ) {
to_select = force_selected_id ;
} else if ( old_selected > = 0 ) {
to_select = old_selected ;
}
// Clear the list.
sources_list - > clear ( ) ;
// Update the atlas sources.
2023-06-22 13:42:45 +00:00
List < int > source_ids = TilesEditorUtils : : get_singleton ( ) - > get_sorted_sources ( tile_set ) ;
2021-11-10 01:27:37 +00:00
for ( const int & source_id : source_ids ) {
2021-05-07 13:41:39 +00:00
TileSetSource * source = * tile_set - > get_source ( source_id ) ;
2021-05-18 13:40:52 +00:00
Ref < Texture2D > texture ;
String item_text ;
2021-10-14 11:28:45 +00:00
// Common to all type of sources.
if ( ! source - > get_name ( ) . is_empty ( ) ) {
2023-07-14 16:25:51 +00:00
item_text = source - > get_name ( ) ;
2021-10-14 11:28:45 +00:00
}
2021-05-18 13:40:52 +00:00
// Atlas source.
2021-05-07 13:41:39 +00:00
TileSetAtlasSource * atlas_source = Object : : cast_to < TileSetAtlasSource > ( source ) ;
if ( atlas_source ) {
2021-05-18 13:40:52 +00:00
texture = atlas_source - > get_texture ( ) ;
2021-10-14 11:28:45 +00:00
if ( item_text . is_empty ( ) ) {
if ( texture . is_valid ( ) ) {
2023-07-14 16:25:51 +00:00
item_text = texture - > get_path ( ) . get_file ( ) ;
2021-10-14 11:28:45 +00:00
} else {
2021-11-10 01:27:37 +00:00
item_text = vformat ( TTR ( " No Texture Atlas Source (ID: %d) " ) , source_id ) ;
2021-10-14 11:28:45 +00:00
}
2021-05-07 13:41:39 +00:00
}
}
2021-05-18 13:40:52 +00:00
// Scene collection source.
TileSetScenesCollectionSource * scene_collection_source = Object : : cast_to < TileSetScenesCollectionSource > ( source ) ;
if ( scene_collection_source ) {
2023-08-13 00:33:39 +00:00
texture = get_editor_theme_icon ( SNAME ( " PackedScene " ) ) ;
2021-10-14 11:28:45 +00:00
if ( item_text . is_empty ( ) ) {
2023-08-18 11:46:58 +00:00
if ( scene_collection_source - > get_scene_tiles_count ( ) > 0 ) {
item_text = vformat ( TTR ( " Scene Collection Source (ID: %d) " ) , source_id ) ;
} else {
item_text = vformat ( TTR ( " Empty Scene Collection Source (ID: %d) " ) , source_id ) ;
}
2021-10-14 11:28:45 +00:00
}
2021-05-18 13:40:52 +00:00
}
// Use default if not valid.
if ( item_text . is_empty ( ) ) {
2021-11-10 01:27:37 +00:00
item_text = vformat ( TTR ( " Unknown Type Source (ID: %d) " ) , source_id ) ;
2021-05-18 13:40:52 +00:00
}
if ( ! texture . is_valid ( ) ) {
texture = missing_texture_texture ;
}
sources_list - > add_item ( item_text , texture ) ;
2022-03-12 00:06:45 +00:00
sources_list - > set_item_metadata ( - 1 , source_id ) ;
2021-05-07 13:41:39 +00:00
}
// Set again the current selected item if needed.
if ( to_select > = 0 ) {
for ( int i = 0 ; i < sources_list - > get_item_count ( ) ; i + + ) {
if ( ( int ) sources_list - > get_item_metadata ( i ) = = to_select ) {
sources_list - > set_current ( i ) ;
2021-11-10 01:27:37 +00:00
sources_list - > ensure_current_is_visible ( ) ;
2021-05-07 13:41:39 +00:00
if ( old_selected ! = to_select ) {
2024-05-14 12:21:31 +00:00
sources_list - > emit_signal ( SceneStringName ( item_selected ) , sources_list - > get_current ( ) ) ;
2021-05-07 13:41:39 +00:00
}
break ;
}
}
}
// If nothing is selected, select the first entry.
if ( sources_list - > get_current ( ) < 0 & & sources_list - > get_item_count ( ) > 0 ) {
sources_list - > set_current ( 0 ) ;
if ( old_selected ! = int ( sources_list - > get_item_metadata ( 0 ) ) ) {
2024-05-14 12:21:31 +00:00
sources_list - > emit_signal ( SceneStringName ( item_selected ) , sources_list - > get_current ( ) ) ;
2021-05-07 13:41:39 +00:00
}
}
// If there is no source left, hide all editors and show the label.
_source_selected ( sources_list - > get_current ( ) ) ;
// Synchronize the lists.
2023-06-22 13:42:45 +00:00
TilesEditorUtils : : get_singleton ( ) - > set_sources_lists_current ( sources_list - > get_current ( ) ) ;
2021-05-07 13:41:39 +00:00
}
void TileSetEditor : : _source_selected ( int p_source_index ) {
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
// Update the selected source.
2022-09-06 12:26:19 +00:00
sources_delete_button - > set_disabled ( p_source_index < 0 | | read_only ) ;
2021-05-07 13:41:39 +00:00
if ( p_source_index > = 0 ) {
int source_id = sources_list - > get_item_metadata ( p_source_index ) ;
TileSetAtlasSource * atlas_source = Object : : cast_to < TileSetAtlasSource > ( * tile_set - > get_source ( source_id ) ) ;
2021-05-18 13:40:52 +00:00
TileSetScenesCollectionSource * scenes_collection_source = Object : : cast_to < TileSetScenesCollectionSource > ( * tile_set - > get_source ( source_id ) ) ;
2021-05-07 13:41:39 +00:00
if ( atlas_source ) {
no_source_selected_label - > hide ( ) ;
2021-05-18 13:40:52 +00:00
tile_set_atlas_source_editor - > edit ( * tile_set , atlas_source , source_id ) ;
2021-05-07 13:41:39 +00:00
tile_set_atlas_source_editor - > show ( ) ;
2021-05-18 13:40:52 +00:00
tile_set_scenes_collection_source_editor - > hide ( ) ;
} else if ( scenes_collection_source ) {
no_source_selected_label - > hide ( ) ;
tile_set_atlas_source_editor - > hide ( ) ;
tile_set_scenes_collection_source_editor - > edit ( * tile_set , scenes_collection_source , source_id ) ;
tile_set_scenes_collection_source_editor - > show ( ) ;
2021-05-07 13:41:39 +00:00
} else {
no_source_selected_label - > show ( ) ;
tile_set_atlas_source_editor - > hide ( ) ;
2021-05-18 13:40:52 +00:00
tile_set_scenes_collection_source_editor - > hide ( ) ;
2021-05-07 13:41:39 +00:00
}
} else {
no_source_selected_label - > show ( ) ;
tile_set_atlas_source_editor - > hide ( ) ;
2021-05-18 13:40:52 +00:00
tile_set_scenes_collection_source_editor - > hide ( ) ;
2021-05-07 13:41:39 +00:00
}
}
2021-07-06 12:43:03 +00:00
void TileSetEditor : : _source_delete_pressed ( ) {
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
// Update the selected source.
int to_delete = sources_list - > get_item_metadata ( sources_list - > get_current ( ) ) ;
Ref < TileSetSource > source = tile_set - > get_source ( to_delete ) ;
// Remove the source.
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2021-07-06 12:43:03 +00:00
undo_redo - > create_action ( TTR ( " Remove source " ) ) ;
undo_redo - > add_do_method ( * tile_set , " remove_source " , to_delete ) ;
undo_redo - > add_undo_method ( * tile_set , " add_source " , source , to_delete ) ;
undo_redo - > commit_action ( ) ;
_update_sources_list ( ) ;
}
2021-05-18 13:40:52 +00:00
void TileSetEditor : : _source_add_id_pressed ( int p_id_pressed ) {
2021-05-07 13:41:39 +00:00
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
2021-05-18 13:40:52 +00:00
switch ( p_id_pressed ) {
case 0 : {
2023-07-10 13:36:00 +00:00
if ( ! texture_file_dialog ) {
texture_file_dialog = memnew ( EditorFileDialog ) ;
add_child ( texture_file_dialog ) ;
2023-07-19 13:38:08 +00:00
texture_file_dialog - > set_file_mode ( EditorFileDialog : : FILE_MODE_OPEN_FILES ) ;
texture_file_dialog - > connect ( " files_selected " , callable_mp ( this , & TileSetEditor : : _load_texture_files ) ) ;
2023-07-10 13:36:00 +00:00
List < String > extensions ;
ResourceLoader : : get_recognized_extensions_for_type ( " Texture2D " , & extensions ) ;
for ( const String & E : extensions ) {
texture_file_dialog - > add_filter ( " *. " + E , E . to_upper ( ) ) ;
}
}
texture_file_dialog - > popup_file_dialog ( ) ;
2021-05-18 13:40:52 +00:00
} break ;
case 1 : {
int source_id = tile_set - > get_next_source_id ( ) ;
Ref < TileSetScenesCollectionSource > scene_collection_source = memnew ( TileSetScenesCollectionSource ) ;
2021-05-07 13:41:39 +00:00
2021-05-18 13:40:52 +00:00
// Add a new source.
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2021-05-18 13:40:52 +00:00
undo_redo - > create_action ( TTR ( " Add atlas source " ) ) ;
undo_redo - > add_do_method ( * tile_set , " add_source " , scene_collection_source , source_id ) ;
undo_redo - > add_undo_method ( * tile_set , " remove_source " , source_id ) ;
undo_redo - > commit_action ( ) ;
2021-07-06 12:43:03 +00:00
_update_sources_list ( source_id ) ;
2021-05-18 13:40:52 +00:00
} break ;
default :
ERR_FAIL ( ) ;
}
2021-05-07 13:41:39 +00:00
}
2021-07-06 12:43:03 +00:00
void TileSetEditor : : _sources_advanced_menu_id_pressed ( int p_id_pressed ) {
2021-05-07 13:41:39 +00:00
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
2021-07-06 12:43:03 +00:00
switch ( p_id_pressed ) {
case 0 : {
atlas_merging_dialog - > update_tile_set ( tile_set ) ;
atlas_merging_dialog - > popup_centered_ratio ( 0.5 ) ;
} break ;
case 1 : {
tile_proxies_manager_dialog - > update_tile_set ( tile_set ) ;
tile_proxies_manager_dialog - > popup_centered_ratio ( 0.5 ) ;
} break ;
}
2021-05-07 13:41:39 +00:00
}
2021-11-10 01:27:37 +00:00
void TileSetEditor : : _set_source_sort ( int p_sort ) {
2023-06-22 13:42:45 +00:00
TilesEditorUtils : : get_singleton ( ) - > set_sorting_option ( p_sort ) ;
for ( int i = 0 ; i ! = TilesEditorUtils : : SOURCE_SORT_MAX ; i + + ) {
2021-11-10 01:27:37 +00:00
source_sort_button - > get_popup ( ) - > set_item_checked ( i , ( i = = ( int ) p_sort ) ) ;
}
int old_selected = TileSet : : INVALID_SOURCE ;
if ( sources_list - > get_current ( ) > = 0 ) {
int source_id = sources_list - > get_item_metadata ( sources_list - > get_current ( ) ) ;
if ( tile_set - > has_source ( source_id ) ) {
old_selected = source_id ;
}
}
_update_sources_list ( old_selected ) ;
2024-03-07 13:36:20 +00:00
if ( ! first_edit ) {
EditorSettings : : get_singleton ( ) - > set_project_metadata ( " editor_metadata " , " tile_source_sort " , p_sort ) ;
}
2021-11-10 01:27:37 +00:00
}
2021-05-07 13:41:39 +00:00
void TileSetEditor : : _notification ( int p_what ) {
switch ( p_what ) {
2022-02-16 14:17:55 +00:00
case NOTIFICATION_THEME_CHANGED : {
2023-08-13 00:33:39 +00:00
sources_delete_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Remove " ) ) ) ;
sources_add_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Add " ) ) ) ;
source_sort_button - > set_icon ( get_editor_theme_icon ( SNAME ( " Sort " ) ) ) ;
sources_advanced_menu_button - > set_icon ( get_editor_theme_icon ( SNAME ( " GuiTabMenuHl " ) ) ) ;
missing_texture_texture = get_editor_theme_icon ( SNAME ( " TileSet " ) ) ;
2024-05-14 13:50:53 +00:00
expanded_area - > add_theme_style_override ( SceneStringName ( panel ) , get_theme_stylebox ( SceneStringName ( panel ) , " Tree " ) ) ;
2022-12-08 04:10:54 +00:00
_update_sources_list ( ) ;
2022-02-16 14:17:55 +00:00
} break ;
case NOTIFICATION_INTERNAL_PROCESS : {
2021-05-07 13:41:39 +00:00
if ( tile_set_changed_needs_update ) {
2021-05-21 08:08:15 +00:00
if ( tile_set . is_valid ( ) ) {
tile_set - > set_edited ( true ) ;
}
2022-09-06 12:26:19 +00:00
read_only = false ;
if ( tile_set . is_valid ( ) ) {
read_only = EditorNode : : get_singleton ( ) - > is_resource_read_only ( tile_set ) ;
}
2021-07-06 12:43:03 +00:00
_update_sources_list ( ) ;
2021-09-29 15:48:27 +00:00
_update_patterns_list ( ) ;
2022-09-06 12:26:19 +00:00
sources_add_button - > set_disabled ( read_only ) ;
sources_advanced_menu_button - > set_disabled ( read_only ) ;
source_sort_button - > set_disabled ( read_only ) ;
2021-05-07 13:41:39 +00:00
tile_set_changed_needs_update = false ;
}
2022-02-16 14:17:55 +00:00
} break ;
2023-07-15 18:58:52 +00:00
case NOTIFICATION_VISIBILITY_CHANGED : {
if ( ! is_visible_in_tree ( ) ) {
remove_expanded_editor ( ) ;
}
} break ;
2021-05-07 13:41:39 +00:00
}
}
2021-09-29 15:48:27 +00:00
void TileSetEditor : : _patterns_item_list_gui_input ( const Ref < InputEvent > & p_event ) {
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
2022-09-06 12:26:19 +00:00
if ( EditorNode : : get_singleton ( ) - > is_resource_read_only ( tile_set ) ) {
return ;
}
2021-09-29 15:48:27 +00:00
if ( ED_IS_SHORTCUT ( " tiles_editor/delete " , p_event ) & & p_event - > is_pressed ( ) & & ! p_event - > is_echo ( ) ) {
Vector < int > selected = patterns_item_list - > get_selected_items ( ) ;
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo = EditorUndoRedoManager : : get_singleton ( ) ;
2021-09-29 15:48:27 +00:00
undo_redo - > create_action ( TTR ( " Remove TileSet patterns " ) ) ;
for ( int i = 0 ; i < selected . size ( ) ; i + + ) {
int pattern_index = selected [ i ] ;
undo_redo - > add_do_method ( * tile_set , " remove_pattern " , pattern_index ) ;
undo_redo - > add_undo_method ( * tile_set , " add_pattern " , tile_set - > get_pattern ( pattern_index ) , pattern_index ) ;
}
undo_redo - > commit_action ( ) ;
patterns_item_list - > accept_event ( ) ;
}
}
void TileSetEditor : : _pattern_preview_done ( Ref < TileMapPattern > p_pattern , Ref < Texture2D > p_texture ) {
// TODO optimize ?
for ( int i = 0 ; i < patterns_item_list - > get_item_count ( ) ; i + + ) {
if ( patterns_item_list - > get_item_metadata ( i ) = = p_pattern ) {
patterns_item_list - > set_item_icon ( i , p_texture ) ;
break ;
}
}
}
void TileSetEditor : : _update_patterns_list ( ) {
ERR_FAIL_COND ( ! tile_set . is_valid ( ) ) ;
// Recreate the items.
patterns_item_list - > clear ( ) ;
for ( int i = 0 ; i < tile_set - > get_patterns_count ( ) ; i + + ) {
int id = patterns_item_list - > add_item ( " " ) ;
patterns_item_list - > set_item_metadata ( id , tile_set - > get_pattern ( i ) ) ;
2023-05-23 10:43:06 +00:00
patterns_item_list - > set_item_tooltip ( id , vformat ( TTR ( " Index: %d " ) , i ) ) ;
2023-06-22 13:42:45 +00:00
TilesEditorUtils : : get_singleton ( ) - > queue_pattern_preview ( tile_set , tile_set - > get_pattern ( i ) , callable_mp ( this , & TileSetEditor : : _pattern_preview_done ) ) ;
2021-09-29 15:48:27 +00:00
}
// Update the label visibility.
patterns_help_label - > set_visible ( patterns_item_list - > get_item_count ( ) = = 0 ) ;
}
2021-05-07 13:41:39 +00:00
void TileSetEditor : : _tile_set_changed ( ) {
tile_set_changed_needs_update = true ;
}
2021-09-29 15:48:27 +00:00
void TileSetEditor : : _tab_changed ( int p_tab_changed ) {
split_container - > set_visible ( p_tab_changed = = 0 ) ;
patterns_item_list - > set_visible ( p_tab_changed = = 1 ) ;
}
2024-02-15 16:25:58 +00:00
void TileSetEditor : : _move_tile_set_array_element ( Object * p_undo_redo , Object * p_edited , const String & p_array_prefix , int p_from_index , int p_to_pos ) {
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo_man = Object : : cast_to < EditorUndoRedoManager > ( p_undo_redo ) ;
ERR_FAIL_NULL ( undo_redo_man ) ;
2021-08-31 08:48:45 +00:00
2022-09-29 09:53:28 +00:00
TileSet * ed_tile_set = Object : : cast_to < TileSet > ( p_edited ) ;
if ( ! ed_tile_set ) {
2021-08-31 08:48:45 +00:00
return ;
}
Vector < String > components = String ( p_array_prefix ) . split ( " / " , true , 2 ) ;
// Compute the array indices to save.
int begin = 0 ;
int end ;
if ( p_array_prefix = = " occlusion_layer_ " ) {
2022-09-29 09:53:28 +00:00
end = ed_tile_set - > get_occlusion_layers_count ( ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_array_prefix = = " physics_layer_ " ) {
2022-09-29 09:53:28 +00:00
end = ed_tile_set - > get_physics_layers_count ( ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_array_prefix = = " terrain_set_ " ) {
2022-09-29 09:53:28 +00:00
end = ed_tile_set - > get_terrain_sets_count ( ) ;
2021-08-31 08:48:45 +00:00
} else if ( components . size ( ) > = 2 & & components [ 0 ] . begins_with ( " terrain_set_ " ) & & components [ 0 ] . trim_prefix ( " terrain_set_ " ) . is_valid_int ( ) & & components [ 1 ] = = " terrain_ " ) {
int terrain_set = components [ 0 ] . trim_prefix ( " terrain_set_ " ) . to_int ( ) ;
2022-09-29 09:53:28 +00:00
end = ed_tile_set - > get_terrains_count ( terrain_set ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_array_prefix = = " navigation_layer_ " ) {
2022-09-29 09:53:28 +00:00
end = ed_tile_set - > get_navigation_layers_count ( ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_array_prefix = = " custom_data_layer_ " ) {
2022-09-29 09:53:28 +00:00
end = ed_tile_set - > get_custom_data_layers_count ( ) ;
2021-08-31 08:48:45 +00:00
} else {
ERR_FAIL_MSG ( " Invalid array prefix for TileSet. " ) ;
}
if ( p_from_index < 0 ) {
// Adding new.
if ( p_to_pos > = 0 ) {
begin = p_to_pos ;
} else {
end = 0 ; // Nothing to save when adding at the end.
}
} else if ( p_to_pos < 0 ) {
// Removing.
begin = p_from_index ;
} else {
// Moving.
begin = MIN ( p_from_index , p_to_pos ) ;
end = MIN ( MAX ( p_from_index , p_to_pos ) + 1 , end ) ;
}
2022-09-29 09:53:28 +00:00
# define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
2023-01-18 14:54:44 +00:00
// Add undo method to adding array element.
if ( p_array_prefix = = " occlusion_layer_ " ) {
if ( p_from_index < 0 ) {
undo_redo_man - > add_undo_method ( ed_tile_set , " remove_occlusion_layer " , p_to_pos < 0 ? ed_tile_set - > get_occlusion_layers_count ( ) : p_to_pos ) ;
}
} else if ( p_array_prefix = = " physics_layer_ " ) {
if ( p_from_index < 0 ) {
undo_redo_man - > add_undo_method ( ed_tile_set , " remove_physics_layer " , p_to_pos < 0 ? ed_tile_set - > get_physics_layers_count ( ) : p_to_pos ) ;
}
} else if ( p_array_prefix = = " terrain_set_ " ) {
if ( p_from_index < 0 ) {
undo_redo_man - > add_undo_method ( ed_tile_set , " remove_terrain_set " , p_to_pos < 0 ? ed_tile_set - > get_terrain_sets_count ( ) : p_to_pos ) ;
}
} else if ( components . size ( ) > = 2 & & components [ 0 ] . begins_with ( " terrain_set_ " ) & & components [ 0 ] . trim_prefix ( " terrain_set_ " ) . is_valid_int ( ) & & components [ 1 ] = = " terrain_ " ) {
int terrain_set = components [ 0 ] . trim_prefix ( " terrain_set_ " ) . to_int ( ) ;
if ( p_from_index < 0 ) {
undo_redo_man - > add_undo_method ( ed_tile_set , " remove_terrain " , terrain_set , p_to_pos < 0 ? ed_tile_set - > get_terrains_count ( terrain_set ) : p_to_pos ) ;
}
} else if ( p_array_prefix = = " navigation_layer_ " ) {
if ( p_from_index < 0 ) {
undo_redo_man - > add_undo_method ( ed_tile_set , " remove_navigation_layer " , p_to_pos < 0 ? ed_tile_set - > get_navigation_layers_count ( ) : p_to_pos ) ;
}
} else if ( p_array_prefix = = " custom_data_layer_ " ) {
if ( p_from_index < 0 ) {
undo_redo_man - > add_undo_method ( ed_tile_set , " remove_custom_data_layer " , p_to_pos < 0 ? ed_tile_set - > get_custom_data_layers_count ( ) : p_to_pos ) ;
}
}
2021-08-31 08:48:45 +00:00
// Save layers' properties.
List < PropertyInfo > properties ;
2022-09-29 09:53:28 +00:00
ed_tile_set - > get_property_list ( & properties ) ;
2021-08-31 08:48:45 +00:00
for ( PropertyInfo pi : properties ) {
if ( pi . name . begins_with ( p_array_prefix ) ) {
String str = pi . name . trim_prefix ( p_array_prefix ) ;
int to_char_index = 0 ;
while ( to_char_index < str . length ( ) ) {
2022-02-04 08:32:20 +00:00
if ( ! is_digit ( str [ to_char_index ] ) ) {
2021-08-31 08:48:45 +00:00
break ;
}
to_char_index + + ;
}
if ( to_char_index > 0 ) {
int array_index = str . left ( to_char_index ) . to_int ( ) ;
if ( array_index > = begin & & array_index < end ) {
2022-09-29 09:53:28 +00:00
ADD_UNDO ( ed_tile_set , pi . name ) ;
2021-08-31 08:48:45 +00:00
}
}
}
}
// Save properties for TileSetAtlasSources tile data
2022-09-29 09:53:28 +00:00
for ( int i = 0 ; i < ed_tile_set - > get_source_count ( ) ; i + + ) {
int source_id = ed_tile_set - > get_source_id ( i ) ;
2021-08-31 08:48:45 +00:00
2022-09-29 09:53:28 +00:00
Ref < TileSetAtlasSource > tas = ed_tile_set - > get_source ( source_id ) ;
2021-08-31 08:48:45 +00:00
if ( tas . is_valid ( ) ) {
for ( int j = 0 ; j < tas - > get_tiles_count ( ) ; j + + ) {
Vector2i tile_id = tas - > get_tile_id ( j ) ;
for ( int k = 0 ; k < tas - > get_alternative_tiles_count ( tile_id ) ; k + + ) {
int alternative_id = tas - > get_alternative_tile_id ( tile_id , k ) ;
2022-01-28 13:26:35 +00:00
TileData * tile_data = tas - > get_tile_data ( tile_id , alternative_id ) ;
2023-09-09 15:24:40 +00:00
ERR_FAIL_NULL ( tile_data ) ;
2021-08-31 08:48:45 +00:00
// Actually saving stuff.
if ( p_array_prefix = = " occlusion_layer_ " ) {
for ( int layer_index = begin ; layer_index < end ; layer_index + + ) {
ADD_UNDO ( tile_data , vformat ( " occlusion_layer_%d/polygon " , layer_index ) ) ;
}
} else if ( p_array_prefix = = " physics_layer_ " ) {
for ( int layer_index = begin ; layer_index < end ; layer_index + + ) {
ADD_UNDO ( tile_data , vformat ( " physics_layer_%d/polygons_count " , layer_index ) ) ;
for ( int polygon_index = 0 ; polygon_index < tile_data - > get_collision_polygons_count ( layer_index ) ; polygon_index + + ) {
ADD_UNDO ( tile_data , vformat ( " physics_layer_%d/polygon_%d/points " , layer_index , polygon_index ) ) ;
ADD_UNDO ( tile_data , vformat ( " physics_layer_%d/polygon_%d/one_way " , layer_index , polygon_index ) ) ;
ADD_UNDO ( tile_data , vformat ( " physics_layer_%d/polygon_%d/one_way_margin " , layer_index , polygon_index ) ) ;
}
}
} else if ( p_array_prefix = = " terrain_set_ " ) {
ADD_UNDO ( tile_data , " terrain_set " ) ;
for ( int terrain_set_index = begin ; terrain_set_index < end ; terrain_set_index + + ) {
for ( int l = 0 ; l < TileSet : : CELL_NEIGHBOR_MAX ; l + + ) {
TileSet : : CellNeighbor bit = TileSet : : CellNeighbor ( l ) ;
2022-02-23 16:25:50 +00:00
if ( tile_data - > is_valid_terrain_peering_bit ( bit ) ) {
2021-08-31 08:48:45 +00:00
ADD_UNDO ( tile_data , " terrains_peering_bit/ " + String ( TileSet : : CELL_NEIGHBOR_ENUM_TO_TEXT [ l ] ) ) ;
}
}
}
} else if ( components . size ( ) > = 2 & & components [ 0 ] . begins_with ( " terrain_set_ " ) & & components [ 0 ] . trim_prefix ( " terrain_set_ " ) . is_valid_int ( ) & & components [ 1 ] = = " terrain_ " ) {
for ( int terrain_index = 0 ; terrain_index < TileSet : : CELL_NEIGHBOR_MAX ; terrain_index + + ) {
TileSet : : CellNeighbor bit = TileSet : : CellNeighbor ( terrain_index ) ;
2022-02-23 16:25:50 +00:00
if ( tile_data - > is_valid_terrain_peering_bit ( bit ) ) {
2021-08-31 08:48:45 +00:00
ADD_UNDO ( tile_data , " terrains_peering_bit/ " + String ( TileSet : : CELL_NEIGHBOR_ENUM_TO_TEXT [ terrain_index ] ) ) ;
}
}
} else if ( p_array_prefix = = " navigation_layer_ " ) {
for ( int layer_index = begin ; layer_index < end ; layer_index + + ) {
ADD_UNDO ( tile_data , vformat ( " navigation_layer_%d/polygon " , layer_index ) ) ;
}
} else if ( p_array_prefix = = " custom_data_layer_ " ) {
for ( int layer_index = begin ; layer_index < end ; layer_index + + ) {
ADD_UNDO ( tile_data , vformat ( " custom_data_%d " , layer_index ) ) ;
}
}
}
}
}
}
# undef ADD_UNDO
2023-01-18 14:54:44 +00:00
// Add do method to add/remove array element.
2021-08-31 08:48:45 +00:00
if ( p_array_prefix = = " occlusion_layer_ " ) {
if ( p_from_index < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " add_occlusion_layer " , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_to_pos < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " remove_occlusion_layer " , p_from_index ) ;
2021-08-31 08:48:45 +00:00
} else {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " move_occlusion_layer " , p_from_index , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
}
} else if ( p_array_prefix = = " physics_layer_ " ) {
if ( p_from_index < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " add_physics_layer " , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_to_pos < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " remove_physics_layer " , p_from_index ) ;
2021-08-31 08:48:45 +00:00
} else {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " move_physics_layer " , p_from_index , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
}
} else if ( p_array_prefix = = " terrain_set_ " ) {
if ( p_from_index < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " add_terrain_set " , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_to_pos < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " remove_terrain_set " , p_from_index ) ;
2021-08-31 08:48:45 +00:00
} else {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " move_terrain_set " , p_from_index , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
}
} else if ( components . size ( ) > = 2 & & components [ 0 ] . begins_with ( " terrain_set_ " ) & & components [ 0 ] . trim_prefix ( " terrain_set_ " ) . is_valid_int ( ) & & components [ 1 ] = = " terrain_ " ) {
int terrain_set = components [ 0 ] . trim_prefix ( " terrain_set_ " ) . to_int ( ) ;
if ( p_from_index < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " add_terrain " , terrain_set , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_to_pos < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " remove_terrain " , terrain_set , p_from_index ) ;
2021-08-31 08:48:45 +00:00
} else {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " move_terrain " , terrain_set , p_from_index , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
}
} else if ( p_array_prefix = = " navigation_layer_ " ) {
if ( p_from_index < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " add_navigation_layer " , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_to_pos < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " remove_navigation_layer " , p_from_index ) ;
2021-08-31 08:48:45 +00:00
} else {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " move_navigation_layer " , p_from_index , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
}
} else if ( p_array_prefix = = " custom_data_layer_ " ) {
if ( p_from_index < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " add_custom_data_layer " , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
} else if ( p_to_pos < 0 ) {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " remove_custom_data_layer " , p_from_index ) ;
2021-08-31 08:48:45 +00:00
} else {
2022-09-29 09:53:28 +00:00
undo_redo_man - > add_do_method ( ed_tile_set , " move_custom_data_layer " , p_from_index , p_to_pos ) ;
2021-08-31 08:48:45 +00:00
}
}
}
2024-02-15 16:25:58 +00:00
void TileSetEditor : : _undo_redo_inspector_callback ( Object * p_undo_redo , Object * p_edited , const String & p_property , const Variant & p_new_value ) {
2022-12-23 22:53:16 +00:00
EditorUndoRedoManager * undo_redo_man = Object : : cast_to < EditorUndoRedoManager > ( p_undo_redo ) ;
ERR_FAIL_NULL ( undo_redo_man ) ;
2021-05-07 13:41:39 +00:00
2022-09-29 09:53:28 +00:00
# define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
TileSet * ed_tile_set = Object : : cast_to < TileSet > ( p_edited ) ;
if ( ed_tile_set ) {
2021-05-07 13:41:39 +00:00
Vector < String > components = p_property . split ( " / " , true , 3 ) ;
2022-09-29 09:53:28 +00:00
for ( int i = 0 ; i < ed_tile_set - > get_source_count ( ) ; i + + ) {
int source_id = ed_tile_set - > get_source_id ( i ) ;
2021-05-07 13:41:39 +00:00
2022-09-29 09:53:28 +00:00
Ref < TileSetAtlasSource > tas = ed_tile_set - > get_source ( source_id ) ;
2021-05-07 13:41:39 +00:00
if ( tas . is_valid ( ) ) {
for ( int j = 0 ; j < tas - > get_tiles_count ( ) ; j + + ) {
Vector2i tile_id = tas - > get_tile_id ( j ) ;
for ( int k = 0 ; k < tas - > get_alternative_tiles_count ( tile_id ) ; k + + ) {
int alternative_id = tas - > get_alternative_tile_id ( tile_id , k ) ;
2022-01-28 13:26:35 +00:00
TileData * tile_data = tas - > get_tile_data ( tile_id , alternative_id ) ;
2023-09-09 15:24:40 +00:00
ERR_FAIL_NULL ( tile_data ) ;
2021-05-07 13:41:39 +00:00
2021-08-31 08:48:45 +00:00
if ( components . size ( ) = = 2 & & components [ 0 ] . begins_with ( " terrain_set_ " ) & & components [ 0 ] . trim_prefix ( " terrain_set_ " ) . is_valid_int ( ) & & components [ 1 ] = = " mode " ) {
2021-05-07 13:41:39 +00:00
ADD_UNDO ( tile_data , " terrain_set " ) ;
2022-02-23 16:25:50 +00:00
ADD_UNDO ( tile_data , " terrain " ) ;
2021-06-09 18:01:08 +00:00
for ( int l = 0 ; l < TileSet : : CELL_NEIGHBOR_MAX ; l + + ) {
TileSet : : CellNeighbor bit = TileSet : : CellNeighbor ( l ) ;
2022-02-23 16:25:50 +00:00
if ( tile_data - > is_valid_terrain_peering_bit ( bit ) ) {
2021-06-09 18:01:08 +00:00
ADD_UNDO ( tile_data , " terrains_peering_bit/ " + String ( TileSet : : CELL_NEIGHBOR_ENUM_TO_TEXT [ l ] ) ) ;
}
2021-05-07 13:41:39 +00:00
}
2021-06-16 16:24:34 +00:00
} else if ( components . size ( ) = = 2 & & components [ 0 ] . begins_with ( " custom_data_layer_ " ) & & components [ 0 ] . trim_prefix ( " custom_data_layer_ " ) . is_valid_int ( ) & & components [ 1 ] = = " type " ) {
int custom_data_layer = components [ 0 ] . trim_prefix ( " custom_data_layer_ " ) . is_valid_int ( ) ;
2021-05-07 13:41:39 +00:00
ADD_UNDO ( tile_data , vformat ( " custom_data_%d " , custom_data_layer ) ) ;
}
}
}
}
}
}
# undef ADD_UNDO
}
void TileSetEditor : : edit ( Ref < TileSet > p_tile_set ) {
2022-09-06 12:26:19 +00:00
bool new_read_only_state = false ;
2023-02-10 00:07:48 +00:00
if ( p_tile_set . is_valid ( ) ) {
2022-09-06 12:26:19 +00:00
new_read_only_state = EditorNode : : get_singleton ( ) - > is_resource_read_only ( p_tile_set ) ;
}
if ( p_tile_set = = tile_set & & new_read_only_state = = read_only ) {
2021-05-07 13:41:39 +00:00
return ;
}
// Remove listener.
if ( tile_set . is_valid ( ) ) {
2023-07-03 19:29:37 +00:00
tile_set - > disconnect_changed ( callable_mp ( this , & TileSetEditor : : _tile_set_changed ) ) ;
2021-05-07 13:41:39 +00:00
}
// Change the edited object.
tile_set = p_tile_set ;
2022-09-06 12:26:19 +00:00
// Read-only status is false by default
read_only = new_read_only_state ;
// Add the listener again and check for read-only status.
2021-05-07 13:41:39 +00:00
if ( tile_set . is_valid ( ) ) {
2022-09-06 12:26:19 +00:00
sources_add_button - > set_disabled ( read_only ) ;
sources_advanced_menu_button - > set_disabled ( read_only ) ;
source_sort_button - > set_disabled ( read_only ) ;
2023-07-03 19:29:37 +00:00
tile_set - > connect_changed ( callable_mp ( this , & TileSetEditor : : _tile_set_changed ) ) ;
2022-10-01 15:32:36 +00:00
if ( first_edit ) {
_set_source_sort ( EditorSettings : : get_singleton ( ) - > get_project_metadata ( " editor_metadata " , " tile_source_sort " , 0 ) ) ;
2024-03-07 13:36:20 +00:00
first_edit = false ;
2022-10-01 15:32:36 +00:00
} else {
_update_sources_list ( ) ;
}
2021-09-29 15:48:27 +00:00
_update_patterns_list ( ) ;
2021-05-07 13:41:39 +00:00
}
}
2023-07-15 18:58:52 +00:00
void TileSetEditor : : add_expanded_editor ( Control * p_editor ) {
expanded_editor = p_editor ;
expanded_editor_parent = p_editor - > get_parent ( ) - > get_instance_id ( ) ;
// Find the scrollable control this node belongs to.
Node * check_parent = expanded_editor - > get_parent ( ) ;
Control * parent_container = nullptr ;
while ( check_parent ) {
parent_container = Object : : cast_to < EditorInspector > ( check_parent ) ;
if ( parent_container ) {
break ;
}
parent_container = Object : : cast_to < ScrollContainer > ( check_parent ) ;
if ( parent_container ) {
break ;
}
check_parent = check_parent - > get_parent ( ) ;
}
ERR_FAIL_NULL ( parent_container ) ;
expanded_editor - > set_meta ( " reparented " , true ) ;
expanded_editor - > reparent ( expanded_area ) ;
expanded_area - > show ( ) ;
expanded_area - > set_size ( Vector2 ( parent_container - > get_global_rect ( ) . get_end ( ) . x - expanded_area - > get_global_position ( ) . x , expanded_area - > get_size ( ) . y ) ) ;
for ( SplitContainer * split : disable_on_expand ) {
split - > set_dragger_visibility ( SplitContainer : : DRAGGER_HIDDEN ) ;
}
}
void TileSetEditor : : remove_expanded_editor ( ) {
if ( ! expanded_editor ) {
return ;
}
Node * original_parent = Object : : cast_to < Node > ( ObjectDB : : get_instance ( expanded_editor_parent ) ) ;
if ( original_parent ) {
expanded_editor - > remove_meta ( " reparented " ) ;
expanded_editor - > reparent ( original_parent ) ;
} else {
expanded_editor - > queue_free ( ) ;
}
expanded_editor = nullptr ;
expanded_editor_parent = ObjectID ( ) ;
expanded_area - > hide ( ) ;
for ( SplitContainer * split : disable_on_expand ) {
split - > set_dragger_visibility ( SplitContainer : : DRAGGER_VISIBLE ) ;
}
}
void TileSetEditor : : register_split ( SplitContainer * p_split ) {
disable_on_expand . push_back ( p_split ) ;
}
2021-05-07 13:41:39 +00:00
TileSetEditor : : TileSetEditor ( ) {
singleton = this ;
set_process_internal ( true ) ;
2023-07-15 18:58:52 +00:00
VBoxContainer * main_vb = memnew ( VBoxContainer ) ;
add_child ( main_vb ) ;
main_vb - > set_anchors_and_offsets_preset ( PRESET_FULL_RECT ) ;
2021-10-17 16:55:44 +00:00
// TabBar.
tabs_bar = memnew ( TabBar ) ;
2022-03-07 14:32:49 +00:00
tabs_bar - > set_tab_alignment ( TabBar : : ALIGNMENT_CENTER ) ;
2021-09-29 15:48:27 +00:00
tabs_bar - > set_clip_tabs ( false ) ;
tabs_bar - > add_tab ( TTR ( " Tiles " ) ) ;
tabs_bar - > add_tab ( TTR ( " Patterns " ) ) ;
tabs_bar - > connect ( " tab_changed " , callable_mp ( this , & TileSetEditor : : _tab_changed ) ) ;
tile_set_toolbar = memnew ( HBoxContainer ) ;
tile_set_toolbar - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
tile_set_toolbar - > add_child ( tabs_bar ) ;
2023-07-15 18:58:52 +00:00
main_vb - > add_child ( tile_set_toolbar ) ;
2021-09-29 15:48:27 +00:00
//// Tiles ////
2021-05-07 13:41:39 +00:00
// Split container.
2021-09-29 15:48:27 +00:00
split_container = memnew ( HSplitContainer ) ;
2021-05-07 13:41:39 +00:00
split_container - > set_name ( TTR ( " Tiles " ) ) ;
split_container - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
split_container - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2023-07-15 18:58:52 +00:00
main_vb - > add_child ( split_container ) ;
2021-05-07 13:41:39 +00:00
// Sources list.
VBoxContainer * split_container_left_side = memnew ( VBoxContainer ) ;
split_container_left_side - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
split_container_left_side - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
split_container_left_side - > set_stretch_ratio ( 0.25 ) ;
2022-08-13 17:22:07 +00:00
split_container_left_side - > set_custom_minimum_size ( Size2 ( 70 , 0 ) * EDSCALE ) ;
2021-05-07 13:41:39 +00:00
split_container - > add_child ( split_container_left_side ) ;
2021-11-10 01:27:37 +00:00
source_sort_button = memnew ( MenuButton ) ;
2023-09-19 16:03:10 +00:00
source_sort_button - > set_flat ( false ) ;
source_sort_button - > set_theme_type_variation ( " FlatButton " ) ;
2022-08-13 14:31:10 +00:00
source_sort_button - > set_tooltip_text ( TTR ( " Sort Sources " ) ) ;
2021-11-10 01:27:37 +00:00
PopupMenu * p = source_sort_button - > get_popup ( ) ;
2024-05-14 12:13:31 +00:00
p - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & TileSetEditor : : _set_source_sort ) ) ;
2023-06-22 13:42:45 +00:00
p - > add_radio_check_item ( TTR ( " Sort by ID (Ascending) " ) , TilesEditorUtils : : SOURCE_SORT_ID ) ;
p - > add_radio_check_item ( TTR ( " Sort by ID (Descending) " ) , TilesEditorUtils : : SOURCE_SORT_ID_REVERSE ) ;
p - > add_radio_check_item ( TTR ( " Sort by Name (Ascending) " ) , TilesEditorUtils : : SOURCE_SORT_NAME ) ;
p - > add_radio_check_item ( TTR ( " Sort by Name (Descending) " ) , TilesEditorUtils : : SOURCE_SORT_NAME_REVERSE ) ;
p - > set_item_checked ( TilesEditorUtils : : SOURCE_SORT_ID , true ) ;
2021-11-10 01:27:37 +00:00
2021-05-07 13:41:39 +00:00
sources_list = memnew ( ItemList ) ;
2024-01-23 21:29:45 +00:00
sources_list - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2022-08-13 17:22:07 +00:00
sources_list - > set_fixed_icon_size ( Size2 ( 60 , 60 ) * EDSCALE ) ;
2021-05-07 13:41:39 +00:00
sources_list - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
sources_list - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2024-05-14 12:21:31 +00:00
sources_list - > connect ( SceneStringName ( item_selected ) , callable_mp ( this , & TileSetEditor : : _source_selected ) ) ;
sources_list - > connect ( SceneStringName ( item_selected ) , callable_mp ( TilesEditorUtils : : get_singleton ( ) , & TilesEditorUtils : : set_sources_lists_current ) ) ;
2024-05-13 14:56:03 +00:00
sources_list - > connect ( SceneStringName ( visibility_changed ) , callable_mp ( TilesEditorUtils : : get_singleton ( ) , & TilesEditorUtils : : synchronize_sources_list ) . bind ( sources_list , source_sort_button ) ) ;
2021-11-10 01:27:37 +00:00
sources_list - > add_user_signal ( MethodInfo ( " sort_request " ) ) ;
2022-07-28 20:56:41 +00:00
sources_list - > connect ( " sort_request " , callable_mp ( this , & TileSetEditor : : _update_sources_list ) . bind ( - 1 ) ) ;
2021-05-18 13:40:52 +00:00
sources_list - > set_texture_filter ( CanvasItem : : TEXTURE_FILTER_NEAREST ) ;
2023-01-14 02:37:19 +00:00
SET_DRAG_FORWARDING_CDU ( sources_list , TileSetEditor ) ;
2021-05-07 13:41:39 +00:00
split_container_left_side - > add_child ( sources_list ) ;
HBoxContainer * sources_bottom_actions = memnew ( HBoxContainer ) ;
2021-11-25 02:58:47 +00:00
sources_bottom_actions - > set_alignment ( BoxContainer : : ALIGNMENT_END ) ;
2021-05-07 13:41:39 +00:00
split_container_left_side - > add_child ( sources_bottom_actions ) ;
sources_delete_button = memnew ( Button ) ;
2023-09-19 16:03:10 +00:00
sources_delete_button - > set_theme_type_variation ( " FlatButton " ) ;
2021-05-07 13:41:39 +00:00
sources_delete_button - > set_disabled ( true ) ;
2024-05-14 07:40:21 +00:00
sources_delete_button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & TileSetEditor : : _source_delete_pressed ) ) ;
2021-05-07 13:41:39 +00:00
sources_bottom_actions - > add_child ( sources_delete_button ) ;
2021-05-18 13:40:52 +00:00
sources_add_button = memnew ( MenuButton ) ;
2023-09-19 16:03:10 +00:00
sources_add_button - > set_flat ( false ) ;
sources_add_button - > set_theme_type_variation ( " FlatButton " ) ;
2021-05-18 13:40:52 +00:00
sources_add_button - > get_popup ( ) - > add_item ( TTR ( " Atlas " ) ) ;
2023-07-26 12:22:26 +00:00
sources_add_button - > get_popup ( ) - > set_item_tooltip ( - 1 , TTR ( " A palette of tiles made from a texture. " ) ) ;
2021-05-18 13:40:52 +00:00
sources_add_button - > get_popup ( ) - > add_item ( TTR ( " Scenes Collection " ) ) ;
2023-07-26 12:22:26 +00:00
sources_add_button - > get_popup ( ) - > set_item_tooltip ( - 1 , TTR ( " A collection of scenes that can be instantiated and placed as tiles. " ) ) ;
2024-05-14 12:13:31 +00:00
sources_add_button - > get_popup ( ) - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & TileSetEditor : : _source_add_id_pressed ) ) ;
2021-05-07 13:41:39 +00:00
sources_bottom_actions - > add_child ( sources_add_button ) ;
2021-07-06 12:43:03 +00:00
sources_advanced_menu_button = memnew ( MenuButton ) ;
2023-09-19 16:03:10 +00:00
sources_advanced_menu_button - > set_flat ( false ) ;
sources_advanced_menu_button - > set_theme_type_variation ( " FlatButton " ) ;
2021-07-06 12:43:03 +00:00
sources_advanced_menu_button - > get_popup ( ) - > add_item ( TTR ( " Open Atlas Merging Tool " ) ) ;
sources_advanced_menu_button - > get_popup ( ) - > add_item ( TTR ( " Manage Tile Proxies " ) ) ;
2024-05-14 12:13:31 +00:00
sources_advanced_menu_button - > get_popup ( ) - > connect ( SceneStringName ( id_pressed ) , callable_mp ( this , & TileSetEditor : : _sources_advanced_menu_id_pressed ) ) ;
2021-07-06 12:43:03 +00:00
sources_bottom_actions - > add_child ( sources_advanced_menu_button ) ;
2021-11-10 01:27:37 +00:00
sources_bottom_actions - > add_child ( source_sort_button ) ;
2021-07-06 12:43:03 +00:00
atlas_merging_dialog = memnew ( AtlasMergingDialog ) ;
add_child ( atlas_merging_dialog ) ;
tile_proxies_manager_dialog = memnew ( TileProxiesManagerDialog ) ;
add_child ( tile_proxies_manager_dialog ) ;
2021-05-18 13:40:52 +00:00
// Right side container.
VBoxContainer * split_container_right_side = memnew ( VBoxContainer ) ;
split_container_right_side - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
split_container_right_side - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
split_container - > add_child ( split_container_right_side ) ;
2021-05-07 13:41:39 +00:00
// No source selected.
no_source_selected_label = memnew ( Label ) ;
2023-06-07 13:59:19 +00:00
no_source_selected_label - > set_text ( TTR ( " No TileSet source selected. Select or create a TileSet source. \n You can create a new source by using the Add button on the left or by dropping a tileset texture onto the source list. " ) ) ;
2021-05-07 13:41:39 +00:00
no_source_selected_label - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
no_source_selected_label - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2021-11-25 02:58:47 +00:00
no_source_selected_label - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
no_source_selected_label - > set_vertical_alignment ( VERTICAL_ALIGNMENT_CENTER ) ;
2021-05-18 13:40:52 +00:00
split_container_right_side - > add_child ( no_source_selected_label ) ;
2021-05-07 13:41:39 +00:00
// Atlases editor.
tile_set_atlas_source_editor = memnew ( TileSetAtlasSourceEditor ) ;
tile_set_atlas_source_editor - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
tile_set_atlas_source_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2021-07-06 12:43:03 +00:00
tile_set_atlas_source_editor - > connect ( " source_id_changed " , callable_mp ( this , & TileSetEditor : : _update_sources_list ) ) ;
2021-05-18 13:40:52 +00:00
split_container_right_side - > add_child ( tile_set_atlas_source_editor ) ;
2021-05-07 13:41:39 +00:00
tile_set_atlas_source_editor - > hide ( ) ;
2021-05-18 13:40:52 +00:00
// Scenes collection editor.
tile_set_scenes_collection_source_editor = memnew ( TileSetScenesCollectionSourceEditor ) ;
tile_set_scenes_collection_source_editor - > set_h_size_flags ( SIZE_EXPAND_FILL ) ;
tile_set_scenes_collection_source_editor - > set_v_size_flags ( SIZE_EXPAND_FILL ) ;
2021-07-06 12:43:03 +00:00
tile_set_scenes_collection_source_editor - > connect ( " source_id_changed " , callable_mp ( this , & TileSetEditor : : _update_sources_list ) ) ;
2021-05-18 13:40:52 +00:00
split_container_right_side - > add_child ( tile_set_scenes_collection_source_editor ) ;
tile_set_scenes_collection_source_editor - > hide ( ) ;
2021-09-29 15:48:27 +00:00
//// Patterns ////
int thumbnail_size = 64 ;
patterns_item_list = memnew ( ItemList ) ;
2024-01-23 21:29:45 +00:00
patterns_item_list - > set_auto_translate_mode ( AUTO_TRANSLATE_MODE_DISABLED ) ;
2021-09-29 15:48:27 +00:00
patterns_item_list - > set_max_columns ( 0 ) ;
patterns_item_list - > set_icon_mode ( ItemList : : ICON_MODE_TOP ) ;
patterns_item_list - > set_fixed_column_width ( thumbnail_size * 3 / 2 ) ;
patterns_item_list - > set_max_text_lines ( 2 ) ;
patterns_item_list - > set_fixed_icon_size ( Size2 ( thumbnail_size , thumbnail_size ) ) ;
patterns_item_list - > set_v_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2024-05-13 14:56:03 +00:00
patterns_item_list - > connect ( SceneStringName ( gui_input ) , callable_mp ( this , & TileSetEditor : : _patterns_item_list_gui_input ) ) ;
2023-07-15 18:58:52 +00:00
main_vb - > add_child ( patterns_item_list ) ;
2021-09-29 15:48:27 +00:00
patterns_item_list - > hide ( ) ;
patterns_help_label = memnew ( Label ) ;
patterns_help_label - > set_text ( TTR ( " Add new patterns in the TileMap editing mode. " ) ) ;
2022-08-13 14:31:10 +00:00
patterns_help_label - > set_horizontal_alignment ( HORIZONTAL_ALIGNMENT_CENTER ) ;
2021-09-29 15:48:27 +00:00
patterns_help_label - > set_anchors_and_offsets_preset ( Control : : PRESET_CENTER ) ;
patterns_item_list - > add_child ( patterns_help_label ) ;
2023-07-15 18:58:52 +00:00
// Expanded editor
expanded_area = memnew ( PanelContainer ) ;
add_child ( expanded_area ) ;
expanded_area - > set_anchors_and_offsets_preset ( PRESET_LEFT_WIDE ) ;
expanded_area - > hide ( ) ;
2021-05-07 13:41:39 +00:00
// Registers UndoRedo inspector callback.
2023-08-11 13:55:47 +00:00
EditorNode : : get_editor_data ( ) . add_move_array_element_function ( SNAME ( " TileSet " ) , callable_mp ( this , & TileSetEditor : : _move_tile_set_array_element ) ) ;
EditorNode : : get_editor_data ( ) . add_undo_redo_inspector_hook_callback ( callable_mp ( this , & TileSetEditor : : _undo_redo_inspector_callback ) ) ;
2021-05-07 13:41:39 +00:00
}
2023-07-14 16:25:51 +00:00
void TileSourceInspectorPlugin : : _show_id_edit_dialog ( Object * p_for_source ) {
if ( ! id_edit_dialog ) {
id_edit_dialog = memnew ( ConfirmationDialog ) ;
TileSetEditor : : get_singleton ( ) - > add_child ( id_edit_dialog ) ;
VBoxContainer * vbox = memnew ( VBoxContainer ) ;
id_edit_dialog - > add_child ( vbox ) ;
Label * label = memnew ( Label ( TTR ( " Warning: Modifying a source ID will result in all TileMaps using that source to reference an invalid source instead. This may result in unexpected data loss. Change this ID carefully. " ) ) ) ;
label - > set_autowrap_mode ( TextServer : : AUTOWRAP_WORD ) ;
vbox - > add_child ( label ) ;
id_input = memnew ( SpinBox ) ;
vbox - > add_child ( id_input ) ;
id_input - > set_max ( INT_MAX ) ;
2024-05-14 12:28:18 +00:00
id_edit_dialog - > connect ( SceneStringName ( confirmed ) , callable_mp ( this , & TileSourceInspectorPlugin : : _confirm_change_id ) ) ;
2023-07-14 16:25:51 +00:00
}
edited_source = p_for_source ;
id_input - > set_value ( p_for_source - > get ( " id " ) ) ;
id_edit_dialog - > popup_centered ( Vector2i ( 400 , 0 ) * EDSCALE ) ;
callable_mp ( ( Control * ) id_input - > get_line_edit ( ) , & Control : : grab_focus ) . call_deferred ( ) ;
}
void TileSourceInspectorPlugin : : _confirm_change_id ( ) {
edited_source - > set ( " id " , id_input - > get_value ( ) ) ;
2023-12-06 22:10:32 +00:00
id_label - > set_text ( itos ( edited_source - > get ( " id " ) ) ) ; // Use get(), because the provided ID might've been invalid.
2023-07-14 16:25:51 +00:00
}
bool TileSourceInspectorPlugin : : can_handle ( Object * p_object ) {
return p_object - > is_class ( " TileSetAtlasSourceProxyObject " ) | | p_object - > is_class ( " TileSetScenesCollectionProxyObject " ) ;
}
bool TileSourceInspectorPlugin : : parse_property ( Object * p_object , const Variant : : Type p_type , const String & p_path , const PropertyHint p_hint , const String & p_hint_text , const BitField < PropertyUsageFlags > p_usage , const bool p_wide ) {
if ( p_path = = " id " ) {
2023-08-01 20:51:52 +00:00
const Variant value = p_object - > get ( " id " ) ;
if ( value . get_type ( ) = = Variant : : NIL ) { // May happen if the object is not yet initialized.
return true ;
}
2023-12-06 22:10:32 +00:00
EditorProperty * ep = memnew ( EditorProperty ) ;
2023-07-14 16:25:51 +00:00
HBoxContainer * hbox = memnew ( HBoxContainer ) ;
hbox - > set_alignment ( BoxContainer : : ALIGNMENT_CENTER ) ;
2023-12-06 22:10:32 +00:00
id_label = memnew ( Label ( itos ( value ) ) ) ;
id_label - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2023-07-14 16:25:51 +00:00
hbox - > add_child ( id_label ) ;
Button * button = memnew ( Button ( TTR ( " Edit " ) ) ) ;
2023-12-06 22:10:32 +00:00
button - > set_h_size_flags ( Control : : SIZE_EXPAND_FILL ) ;
2023-07-14 16:25:51 +00:00
hbox - > add_child ( button ) ;
2024-05-14 07:40:21 +00:00
button - > connect ( SceneStringName ( pressed ) , callable_mp ( this , & TileSourceInspectorPlugin : : _show_id_edit_dialog ) . bind ( p_object ) ) ;
2023-07-14 16:25:51 +00:00
2023-12-06 22:10:32 +00:00
ep - > add_child ( hbox ) ;
add_property_editor ( p_path , ep ) ;
2023-07-14 16:25:51 +00:00
return true ;
}
return false ;
}