@ -73,34 +73,21 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
// Show only the correct settings.
if ( tool_buttons_group - > get_pressed_button ( ) = = select_tool_button ) {
} else if ( tool_buttons_group - > get_pressed_button ( ) = = paint_tool_button ) {
transform_toolbar - > show ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) ! = bucket_tool_button ) {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
transform_toolbar - > show ( ) ;
tools_settings_vsep_2 - > show ( ) ;
random_tile_toggle - > show ( ) ;
scatter_label - > show ( ) ;
scatter_spinbox - > show ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) = = line_tool_button ) {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
tools_settings_vsep_2 - > show ( ) ;
random_tile_toggle - > show ( ) ;
scatter_label - > show ( ) ;
scatter_spinbox - > show ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) = = rect_tool_button ) {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
tools_settings_vsep_2 - > show ( ) ;
random_tile_toggle - > show ( ) ;
scatter_label - > show ( ) ;
scatter_spinbox - > show ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) = = bucket_tool_button ) {
} else {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
transform_toolbar - > show ( ) ;
tools_settings_vsep_2 - > show ( ) ;
bucket_contiguous_checkbox - > show ( ) ;
random_tile_toggle - > show ( ) ;
@ -109,6 +96,31 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
}
}
void TileMapEditorTilesPlugin : : _update_transform_buttons ( ) {
TileMap * tile_map = Object : : cast_to < TileMap > ( ObjectDB : : get_instance ( tile_map_id ) ) ;
if ( ! tile_map ) {
return ;
}
Ref < TileSet > tile_set = tile_map - > get_tileset ( ) ;
if ( tile_set . is_null ( ) | | selection_pattern . is_null ( ) ) {
return ;
}
if ( tile_set - > get_tile_shape ( ) = = TileSet : : TILE_SHAPE_SQUARE | | selection_pattern - > get_size ( ) = = Vector2i ( 1 , 1 ) ) {
transform_button_rotate_left - > set_disabled ( false ) ;
transform_button_rotate_left - > set_tooltip_text ( " " ) ;
transform_button_rotate_right - > set_disabled ( false ) ;
transform_button_rotate_right - > set_tooltip_text ( " " ) ;
} else {
const String tooltip_text = TTR ( " Can't rotate patterns when using non-square tile grid. " ) ;
transform_button_rotate_left - > set_disabled ( true ) ;
transform_button_rotate_left - > set_tooltip_text ( tooltip_text ) ;
transform_button_rotate_right - > set_disabled ( true ) ;
transform_button_rotate_right - > set_tooltip_text ( tooltip_text ) ;
}
}
Vector < TileMapSubEditorPlugin : : TabData > TileMapEditorTilesPlugin : : get_tabs ( ) const {
Vector < TileMapSubEditorPlugin : : TabData > tabs ;
tabs . push_back ( { toolbar , tiles_bottom_panel } ) ;
@ -480,6 +492,11 @@ void TileMapEditorTilesPlugin::_update_theme() {
erase_button - > set_icon ( tiles_bottom_panel - > get_editor_theme_icon ( SNAME ( " Eraser " ) ) ) ;
random_tile_toggle - > set_icon ( tiles_bottom_panel - > get_editor_theme_icon ( SNAME ( " RandomNumberGenerator " ) ) ) ;
transform_button_rotate_left - > set_icon ( tiles_bottom_panel - > get_editor_theme_icon ( " RotateLeft " ) ) ;
transform_button_rotate_right - > set_icon ( tiles_bottom_panel - > get_editor_theme_icon ( " RotateRight " ) ) ;
transform_button_flip_h - > set_icon ( tiles_bottom_panel - > get_editor_theme_icon ( " MirrorX " ) ) ;
transform_button_flip_v - > set_icon ( tiles_bottom_panel - > get_editor_theme_icon ( " MirrorY " ) ) ;
missing_atlas_texture_icon = tiles_bottom_panel - > get_editor_theme_icon ( SNAME ( " TileSet " ) ) ;
_update_tile_set_sources_list ( ) ;
}
@ -573,8 +590,17 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
Ref < InputEventKey > k = p_event ;
if ( k . is_valid ( ) & & k - > is_pressed ( ) & & ! k - > is_echo ( ) ) {
for ( BaseButton * b : viewport_shortcut_buttons ) {
if ( b - > is_disabled ( ) ) {
continue ;
}
if ( b - > get_shortcut ( ) . is_valid ( ) & & b - > get_shortcut ( ) - > matches_event ( p_event ) ) {
b - > set_pressed ( b - > get_button_group ( ) . is_valid ( ) | | ! b - > is_pressed ( ) ) ;
if ( b - > is_toggle_mode ( ) ) {
b - > set_pressed ( b - > get_button_group ( ) . is_valid ( ) | | ! b - > is_pressed ( ) ) ;
} else {
// Can't press a button without toggle mode, so just emit the signal directly.
b - > emit_signal ( SNAME ( " pressed " ) ) ;
}
return true ;
}
}
@ -924,18 +950,18 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Rect2 dest_rect ;
dest_rect . size = source_rect . size ;
bool transpose = tile_data - > get_transpose ( ) ;
bool transpose = tile_data - > get_transpose ( ) ^ bool ( E . value . alternative_tile & TileSetAtlasSource : : TRANSFORM_TRANSPOSE ) ;
if ( transpose ) {
dest_rect . position = ( tile_map - > map_to_local ( E . key ) - Vector2 ( dest_rect . size . y , dest_rect . size . x ) / 2 - tile_offset ) ;
} else {
dest_rect . position = ( tile_map - > map_to_local ( E . key ) - dest_rect . size / 2 - tile_offset ) ;
}
if ( tile_data - > get_flip_h ( ) ) {
if ( tile_data - > get_flip_h ( ) ^ bool ( E . value . alternative_tile & TileSetAtlasSource : : TRANSFORM_FLIP_H ) ) {
dest_rect . size . x = - dest_rect . size . x ;
}
if ( tile_data - > get_flip_v ( ) ) {
if ( tile_data - > get_flip_v ( ) ^ bool ( E . value . alternative_tile & TileSetAtlasSource : : TRANSFORM_FLIP_V ) ) {
dest_rect . size . y = - dest_rect . size . y ;
}
@ -1475,6 +1501,94 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
drag_type = DRAG_TYPE_NONE ;
}
void TileMapEditorTilesPlugin : : _apply_transform ( int p_type ) {
if ( selection_pattern . is_null ( ) | | selection_pattern - > is_empty ( ) ) {
return ;
}
Ref < TileMapPattern > transformed_pattern ;
transformed_pattern . instantiate ( ) ;
bool keep_shape = selection_pattern - > get_size ( ) = = Vector2i ( 1 , 1 ) ;
Vector2i size = selection_pattern - > get_size ( ) ;
for ( int y = 0 ; y < size . y ; y + + ) {
for ( int x = 0 ; x < size . x ; x + + ) {
Vector2i src_coords = Vector2i ( x , y ) ;
if ( ! selection_pattern - > has_cell ( src_coords ) ) {
continue ;
}
Vector2i dst_coords ;
if ( keep_shape ) {
dst_coords = src_coords ;
} else if ( p_type = = TRANSFORM_ROTATE_LEFT ) {
dst_coords = Vector2i ( y , size . x - x - 1 ) ;
} else if ( p_type = = TRANSFORM_ROTATE_RIGHT ) {
dst_coords = Vector2i ( size . y - y - 1 , x ) ;
} else if ( p_type = = TRANSFORM_FLIP_H ) {
dst_coords = Vector2i ( size . x - x - 1 , y ) ;
} else if ( p_type = = TRANSFORM_FLIP_V ) {
dst_coords = Vector2i ( x , size . y - y - 1 ) ;
}
transformed_pattern - > set_cell ( dst_coords ,
selection_pattern - > get_cell_source_id ( src_coords ) , selection_pattern - > get_cell_atlas_coords ( src_coords ) ,
_get_transformed_alternative ( selection_pattern - > get_cell_alternative_tile ( src_coords ) , p_type ) ) ;
}
}
selection_pattern = transformed_pattern ;
CanvasItemEditor : : get_singleton ( ) - > update_viewport ( ) ;
}
int TileMapEditorTilesPlugin : : _get_transformed_alternative ( int p_alternative_id , int p_transform ) {
bool transform_flip_h = p_alternative_id & TileSetAtlasSource : : TRANSFORM_FLIP_H ;
bool transform_flip_v = p_alternative_id & TileSetAtlasSource : : TRANSFORM_FLIP_V ;
bool transform_transpose = p_alternative_id & TileSetAtlasSource : : TRANSFORM_TRANSPOSE ;
switch ( p_transform ) {
case TRANSFORM_ROTATE_LEFT :
case TRANSFORM_ROTATE_RIGHT : {
// A matrix with every possible flip/transpose combination, sorted by what comes next when you rotate.
const LocalVector < bool > rotation_matrix = {
0 , 0 , 0 ,
0 , 1 , 1 ,
1 , 1 , 0 ,
1 , 0 , 1 ,
1 , 0 , 0 ,
0 , 0 , 1 ,
0 , 1 , 0 ,
1 , 1 , 1
} ;
for ( int i = 0 ; i < 8 ; i + + ) {
if ( transform_flip_h = = rotation_matrix [ i * 3 ] & & transform_flip_v = = rotation_matrix [ i * 3 + 1 ] & & transform_transpose = = rotation_matrix [ i * 3 + 2 ] ) {
if ( p_transform = = TRANSFORM_ROTATE_LEFT ) {
i = i / 4 * 4 + ( i + 1 ) % 4 ;
} else {
i = i / 4 * 4 + Math : : posmod ( i - 1 , 4 ) ;
}
transform_flip_h = rotation_matrix [ i * 3 ] ;
transform_flip_v = rotation_matrix [ i * 3 + 1 ] ;
transform_transpose = rotation_matrix [ i * 3 + 2 ] ;
break ;
}
}
} break ;
case TRANSFORM_FLIP_H : {
transform_flip_h = ! transform_flip_h ;
} break ;
case TRANSFORM_FLIP_V : {
transform_flip_v = ! transform_flip_v ;
} break ;
}
return TileSetAtlasSource : : alternative_no_transform ( p_alternative_id ) |
int ( transform_flip_h ) * TileSetAtlasSource : : TRANSFORM_FLIP_H |
int ( transform_flip_v ) * TileSetAtlasSource : : TRANSFORM_FLIP_V |
int ( transform_transpose ) * TileSetAtlasSource : : TRANSFORM_TRANSPOSE ;
}
void TileMapEditorTilesPlugin : : _update_fix_selected_and_hovered ( ) {
TileMap * tile_map = Object : : cast_to < TileMap > ( ObjectDB : : get_instance ( tile_map_id ) ) ;
if ( ! tile_map ) {
@ -1589,6 +1703,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection(
coords_array . push_back ( E ) ;
}
selection_pattern = tile_map - > get_pattern ( tile_map_layer , coords_array ) ;
_update_transform_buttons ( ) ;
}
void TileMapEditorTilesPlugin : : _update_selection_pattern_from_tileset_tiles_selection ( ) {
@ -1662,6 +1777,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_sele
vertical_offset + = MAX ( organized_size . y , 1 ) ;
}
CanvasItemEditor : : get_singleton ( ) - > update_viewport ( ) ;
_update_transform_buttons ( ) ;
}
void TileMapEditorTilesPlugin : : _update_selection_pattern_from_tileset_pattern_selection ( ) {
@ -1700,6 +1816,7 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern(
_update_source_display ( ) ;
tile_atlas_control - > queue_redraw ( ) ;
alternative_tiles_control - > queue_redraw ( ) ;
_update_transform_buttons ( ) ;
}
void TileMapEditorTilesPlugin : : _tile_atlas_control_draw ( ) {
@ -2161,6 +2278,39 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
tools_settings - > add_child ( erase_button ) ;
viewport_shortcut_buttons . push_back ( erase_button ) ;
// Transform toolbar.
transform_toolbar = memnew ( HBoxContainer ) ;
tools_settings - > add_child ( transform_toolbar ) ;
transform_toolbar - > add_child ( memnew ( VSeparator ) ) ;
transform_button_rotate_left = memnew ( Button ) ;
transform_button_rotate_left - > set_flat ( true ) ;
transform_button_rotate_left - > set_shortcut ( ED_SHORTCUT ( " tiles_editor/rotate_tile_left " , TTR ( " Rotate Tile Left " ) , Key : : Z ) ) ;
transform_toolbar - > add_child ( transform_button_rotate_left ) ;
transform_button_rotate_left - > connect ( " pressed " , callable_mp ( this , & TileMapEditorTilesPlugin : : _apply_transform ) . bind ( TRANSFORM_ROTATE_LEFT ) ) ;
viewport_shortcut_buttons . push_back ( transform_button_rotate_left ) ;
transform_button_rotate_right = memnew ( Button ) ;
transform_button_rotate_right - > set_flat ( true ) ;
transform_button_rotate_right - > set_shortcut ( ED_SHORTCUT ( " tiles_editor/rotate_tile_right " , TTR ( " Rotate Tile Right " ) , Key : : X ) ) ;
transform_toolbar - > add_child ( transform_button_rotate_right ) ;
transform_button_rotate_right - > connect ( " pressed " , callable_mp ( this , & TileMapEditorTilesPlugin : : _apply_transform ) . bind ( TRANSFORM_ROTATE_RIGHT ) ) ;
viewport_shortcut_buttons . push_back ( transform_button_rotate_right ) ;
transform_button_flip_h = memnew ( Button ) ;
transform_button_flip_h - > set_flat ( true ) ;
transform_button_flip_h - > set_shortcut ( ED_SHORTCUT ( " tiles_editor/flip_tile_horizontal " , TTR ( " Flip Tile Horizontally " ) , Key : : C ) ) ;
transform_toolbar - > add_child ( transform_button_flip_h ) ;
transform_button_flip_h - > connect ( " pressed " , callable_mp ( this , & TileMapEditorTilesPlugin : : _apply_transform ) . bind ( TRANSFORM_FLIP_H ) ) ;
viewport_shortcut_buttons . push_back ( transform_button_flip_h ) ;
transform_button_flip_v = memnew ( Button ) ;
transform_button_flip_v - > set_flat ( true ) ;
transform_button_flip_v - > set_shortcut ( ED_SHORTCUT ( " tiles_editor/flip_tile_vertical " , TTR ( " Flip Tile Vertically " ) , Key : : V ) ) ;
transform_toolbar - > add_child ( transform_button_flip_v ) ;
transform_button_flip_v - > connect ( " pressed " , callable_mp ( this , & TileMapEditorTilesPlugin : : _apply_transform ) . bind ( TRANSFORM_FLIP_V ) ) ;
viewport_shortcut_buttons . push_back ( transform_button_flip_v ) ;
// Separator 2.
tools_settings_vsep_2 = memnew ( VSeparator ) ;
tools_settings - > add_child ( tools_settings_vsep_2 ) ;
@ -2352,25 +2502,11 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() {
}
// Show only the correct settings.
if ( tool_buttons_group - > get_pressed_button ( ) = = paint_tool_button ) {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
tools_settings_vsep_2 - > hide ( ) ;
bucket_contiguous_checkbox - > hide ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) = = line_tool_button ) {
if ( tool_buttons_group - > get_pressed_button ( ) ! = bucket_tool_button ) {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
tools_settings_vsep_2 - > hide ( ) ;
bucket_contiguous_checkbox - > hide ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) = = rect_tool_button ) {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
tools_settings_vsep_2 - > hide ( ) ;
bucket_contiguous_checkbox - > hide ( ) ;
} else if ( tool_buttons_group - > get_pressed_button ( ) = = bucket_tool_button ) {
} else {
tools_settings_vsep - > show ( ) ;
picker_button - > show ( ) ;
erase_button - > show ( ) ;
@ -3496,7 +3632,6 @@ TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() {
void TileMapEditor : : _notification ( int p_what ) {
switch ( p_what ) {
case NOTIFICATION_ENTER_TREE :
case NOTIFICATION_THEME_CHANGED : {
missing_tile_texture = get_editor_theme_icon ( SNAME ( " StatusWarning " ) ) ;
warning_pattern_texture = get_editor_theme_icon ( SNAME ( " WarningPattern " ) ) ;