diff --git a/Translations/Translations.pot b/Translations/Translations.pot index 4111a5777..c59b716d3 100644 --- a/Translations/Translations.pot +++ b/Translations/Translations.pot @@ -3401,3 +3401,23 @@ msgstr "" #: src/UI/Timeline/NewTileMapLayerDialog.tscn msgid "Tile size:" msgstr "" + +#: src/UI/TilesPanel.tscn +msgid "Draw tiles" +msgstr "" + +#: src/UI/TilesPanel.tscn +msgid "Rotate tile left (counterclockwise)" +msgstr "" + +#: src/UI/TilesPanel.tscn +msgid "Rotate tile right (clockwise)" +msgstr "" + +#: src/UI/TilesPanel.tscn +msgid "Flip tile horizontally" +msgstr "" + +#: src/UI/TilesPanel.tscn +msgid "Flip tile vertically" +msgstr "" diff --git a/assets/graphics/misc/mirror_x.svg b/assets/graphics/misc/mirror_x.svg new file mode 100644 index 000000000..c73996a39 --- /dev/null +++ b/assets/graphics/misc/mirror_x.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/graphics/misc/mirror_x.svg.import b/assets/graphics/misc/mirror_x.svg.import new file mode 100644 index 000000000..96239f95f --- /dev/null +++ b/assets/graphics/misc/mirror_x.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bpsfilx47bw3r" +path="res://.godot/imported/mirror_x.svg-16a0646fb607af92a2ccf231dd0f1d98.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/misc/mirror_x.svg" +dest_files=["res://.godot/imported/mirror_x.svg-16a0646fb607af92a2ccf231dd0f1d98.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/assets/graphics/misc/mirror_y.svg b/assets/graphics/misc/mirror_y.svg new file mode 100644 index 000000000..7f8787231 --- /dev/null +++ b/assets/graphics/misc/mirror_y.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/graphics/misc/mirror_y.svg.import b/assets/graphics/misc/mirror_y.svg.import new file mode 100644 index 000000000..eef8847d9 --- /dev/null +++ b/assets/graphics/misc/mirror_y.svg.import @@ -0,0 +1,37 @@ +[remap] + +importer="texture" +type="CompressedTexture2D" +uid="uid://bk6iaxiyl74ih" +path="res://.godot/imported/mirror_y.svg-47cb90f0f94e4ed7c37f151a9ddbaab0.ctex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://assets/graphics/misc/mirror_y.svg" +dest_files=["res://.godot/imported/mirror_y.svg-47cb90f0f94e4ed7c37f151a9ddbaab0.ctex"] + +[params] + +compress/mode=0 +compress/high_quality=false +compress/lossy_quality=0.7 +compress/hdr_compression=1 +compress/normal_map=0 +compress/channel_pack=0 +mipmaps/generate=false +mipmaps/limit=-1 +roughness/mode=0 +roughness/src_normal="" +process/fix_alpha_border=true +process/premult_alpha=false +process/normal_map_invert_y=false +process/hdr_as_srgb=false +process/hdr_clamp_exposure=false +process/size_limit=0 +detect_3d/compress_to=1 +svg/scale=1.0 +editor/scale_with_editor_scale=false +editor/convert_colors_with_editor_theme=false diff --git a/project.godot b/project.godot index 6c4397d44..a899ba5a1 100644 --- a/project.godot +++ b/project.godot @@ -908,7 +908,7 @@ previous_project={ } center_canvas={ "deadzone": 0.5, -"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":67,"physical_keycode":0,"key_label":0,"unicode":67,"location":0,"echo":false,"script":null) +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":66,"physical_keycode":0,"key_label":0,"unicode":66,"location":0,"echo":false,"script":null) ] } left_text_tool={ @@ -925,6 +925,26 @@ show_pixel_indices={ "deadzone": 0.5, "events": [] } +tile_rotate_left={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":90,"key_label":0,"unicode":90,"location":0,"echo":false,"script":null) +] +} +tile_rotate_right={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":88,"key_label":0,"unicode":88,"location":0,"echo":false,"script":null) +] +} +tile_flip_horizontal={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":67,"key_label":0,"unicode":67,"location":0,"echo":false,"script":null) +] +} +tile_flip_vertical={ +"deadzone": 0.5, +"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":true,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":86,"key_label":0,"unicode":86,"location":0,"echo":false,"script":null) +] +} [input_devices] diff --git a/src/Autoload/Global.gd b/src/Autoload/Global.gd index e55f4fef1..295ec1457 100644 --- a/src/Autoload/Global.gd +++ b/src/Autoload/Global.gd @@ -897,12 +897,17 @@ func _initialize_keychain() -> void: &"reference_rotate": Keychain.InputAction.new("", "Reference images", false), &"reference_scale": Keychain.InputAction.new("", "Reference images", false), &"reference_quick_menu": Keychain.InputAction.new("", "Reference images", false), - &"cancel_reference_transform": Keychain.InputAction.new("", "Reference images", false) + &"cancel_reference_transform": Keychain.InputAction.new("", "Reference images", false), + &"tile_rotate_left": Keychain.InputAction.new("", "Tileset panel", false), + &"tile_rotate_right": Keychain.InputAction.new("", "Tileset panel", false), + &"tile_flip_horizontal": Keychain.InputAction.new("", "Tileset panel", false), + &"tile_flip_vertical": Keychain.InputAction.new("", "Tileset panel", false) } Keychain.groups = { "Canvas": Keychain.InputGroup.new("", false), "Cursor movement": Keychain.InputGroup.new("Canvas"), + "Reference images": Keychain.InputGroup.new("Canvas"), "Buttons": Keychain.InputGroup.new(), "Tools": Keychain.InputGroup.new(), "Left": Keychain.InputGroup.new("Tools"), @@ -921,7 +926,7 @@ func _initialize_keychain() -> void: "Shape tools": Keychain.InputGroup.new("Tool modifiers"), "Selection tools": Keychain.InputGroup.new("Tool modifiers"), "Transformation tools": Keychain.InputGroup.new("Tool modifiers"), - "Reference images": Keychain.InputGroup.new("Canvas") + "Tileset panel": Keychain.InputGroup.new() } Keychain.ignore_actions = ["left_mouse", "right_mouse", "middle_mouse", "shift", "ctrl"] diff --git a/src/UI/TilesPanel.gd b/src/UI/TilesPanel.gd index 89477fee6..5fbb37b44 100644 --- a/src/UI/TilesPanel.gd +++ b/src/UI/TilesPanel.gd @@ -6,6 +6,13 @@ enum TileEditingMode { MANUAL, AUTO, STACK } const TRANSPARENT_CHECKER := preload("res://src/UI/Nodes/TransparentChecker.tscn") const MIN_BUTTON_SIZE := 36 const MAX_BUTTON_SIZE := 144 +## A matrix with every possible flip/transpose combination, +## sorted by what comes next when you rotate. +## Taken from Godot's rotation matrix found in: +## https://github.com/godotengine/godot/blob/master/editor/plugins/tiles/tile_map_layer_editor.cpp +const ROTATION_MATRIX: Array[bool] = [ + 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1 +] static var placing_tiles := false: set(value): @@ -41,12 +48,15 @@ var button_size := 36: button.size = Vector2(button_size, button_size) @onready var place_tiles: CheckBox = $VBoxContainer/PlaceTiles +@onready var transform_buttons_container: HFlowContainer = $VBoxContainer/TransformButtonsContainer @onready var tile_button_container: HFlowContainer = %TileButtonContainer func _ready() -> void: Tools.selected_tile_index_changed.connect(select_tile) Global.cel_switched.connect(_on_cel_switched) + for child: Button in transform_buttons_container.get_children(): + Global.disable_button(child, true) func _gui_input(event: InputEvent) -> void: @@ -147,6 +157,8 @@ func _clear_tile_buttons() -> void: func _on_place_tiles_toggled(toggled_on: bool) -> void: placing_tiles = toggled_on + for child: Button in transform_buttons_container.get_children(): + Global.disable_button(child, not toggled_on) func _on_manual_toggled(toggled_on: bool) -> void: @@ -164,13 +176,29 @@ func _on_stack_toggled(toggled_on: bool) -> void: tile_editing_mode = TileEditingMode.STACK -func _on_flip_horizontal_button_toggled(toggled_on: bool) -> void: - is_flipped_h = toggled_on +func _on_flip_horizontal_button_pressed() -> void: + is_flipped_h = not is_flipped_h -func _on_flip_vertical_button_toggled(toggled_on: bool) -> void: - is_flipped_v = toggled_on +func _on_flip_vertical_button_pressed() -> void: + is_flipped_v = not is_flipped_v -func _on_transpose_button_toggled(toggled_on: bool) -> void: - is_transposed = toggled_on +func _on_rotate_pressed(clockwise: bool) -> void: + for i in ROTATION_MATRIX.size(): + var final_i := i + if ( + is_flipped_h == ROTATION_MATRIX[i * 3] + && is_flipped_v == ROTATION_MATRIX[i * 3 + 1] + && is_transposed == ROTATION_MATRIX[i * 3 + 2] + ): + if clockwise: + @warning_ignore("integer_division") + final_i = i / 4 * 4 + posmod(i - 1, 4) + else: + @warning_ignore("integer_division") + final_i = i / 4 * 4 + (i + 1) % 4 + is_flipped_h = ROTATION_MATRIX[final_i * 3] + is_flipped_v = ROTATION_MATRIX[final_i * 3 + 1] + is_transposed = ROTATION_MATRIX[final_i * 3 + 2] + break diff --git a/src/UI/TilesPanel.tscn b/src/UI/TilesPanel.tscn index 5e1c4dcf9..d92e5f031 100644 --- a/src/UI/TilesPanel.tscn +++ b/src/UI/TilesPanel.tscn @@ -1,6 +1,33 @@ -[gd_scene load_steps=3 format=3 uid="uid://bfbragmmdwfbl"] +[gd_scene load_steps=14 format=3 uid="uid://bfbragmmdwfbl"] [ext_resource type="Script" path="res://src/UI/TilesPanel.gd" id="1_d2oc5"] +[ext_resource type="Texture2D" uid="uid://bv7ldl8obhawm" path="res://assets/graphics/misc/icon_reload.png" id="2_r1kie"] +[ext_resource type="Texture2D" uid="uid://bpsfilx47bw3r" path="res://assets/graphics/misc/mirror_x.svg" id="3_5o62r"] +[ext_resource type="Texture2D" uid="uid://bk6iaxiyl74ih" path="res://assets/graphics/misc/mirror_y.svg" id="4_2xhnr"] + +[sub_resource type="InputEventAction" id="InputEventAction_yr0lx"] +action = &"tile_rotate_left" + +[sub_resource type="Shortcut" id="Shortcut_yas23"] +events = [SubResource("InputEventAction_yr0lx")] + +[sub_resource type="InputEventAction" id="InputEventAction_g6d5p"] +action = &"tile_rotate_right" + +[sub_resource type="Shortcut" id="Shortcut_cmy2w"] +events = [SubResource("InputEventAction_g6d5p")] + +[sub_resource type="InputEventAction" id="InputEventAction_yh67l"] +action = &"tile_flip_horizontal" + +[sub_resource type="Shortcut" id="Shortcut_ouoxo"] +events = [SubResource("InputEventAction_yh67l")] + +[sub_resource type="InputEventAction" id="InputEventAction_18g3a"] +action = &"tile_flip_vertical" + +[sub_resource type="Shortcut" id="Shortcut_jj4yy"] +events = [SubResource("InputEventAction_18g3a")] [sub_resource type="ButtonGroup" id="ButtonGroup_uxnt0"] @@ -18,28 +45,79 @@ layout_mode = 2 [node name="PlaceTiles" type="CheckBox" parent="VBoxContainer"] layout_mode = 2 mouse_default_cursor_shape = 2 -text = "Place tiles" +text = "Draw tiles" [node name="TransformButtonsContainer" type="HFlowContainer" parent="VBoxContainer"] layout_mode = 2 -[node name="FlipHorizontalButton" type="Button" parent="VBoxContainer/TransformButtonsContainer"] +[node name="RotateLeftButton" type="Button" parent="VBoxContainer/TransformButtonsContainer" groups=["UIButtons"]] +custom_minimum_size = Vector2(24, 24) layout_mode = 2 +tooltip_text = "Rotate tile left (counterclockwise)" mouse_default_cursor_shape = 2 -toggle_mode = true -text = "H" +shortcut = SubResource("Shortcut_yas23") -[node name="FlipVerticalButton" type="Button" parent="VBoxContainer/TransformButtonsContainer"] -layout_mode = 2 -mouse_default_cursor_shape = 2 -toggle_mode = true -text = "V" +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/TransformButtonsContainer/RotateLeftButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("2_r1kie") +stretch_mode = 3 -[node name="TransposeButton" type="Button" parent="VBoxContainer/TransformButtonsContainer"] +[node name="RotateRightButton" type="Button" parent="VBoxContainer/TransformButtonsContainer" groups=["UIButtons"]] +custom_minimum_size = Vector2(24, 24) layout_mode = 2 +tooltip_text = "Rotate tile right (clockwise)" mouse_default_cursor_shape = 2 -toggle_mode = true -text = "T" +shortcut = SubResource("Shortcut_cmy2w") + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/TransformButtonsContainer/RotateRightButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("2_r1kie") +stretch_mode = 3 +flip_h = true + +[node name="FlipHorizontalButton" type="Button" parent="VBoxContainer/TransformButtonsContainer" groups=["UIButtons"]] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +tooltip_text = "Flip tile horizontally" +mouse_default_cursor_shape = 2 +shortcut = SubResource("Shortcut_ouoxo") + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/TransformButtonsContainer/FlipHorizontalButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("3_5o62r") +stretch_mode = 3 + +[node name="FlipVerticalButton" type="Button" parent="VBoxContainer/TransformButtonsContainer" groups=["UIButtons"]] +custom_minimum_size = Vector2(24, 24) +layout_mode = 2 +tooltip_text = "Flip tile vertically" +mouse_default_cursor_shape = 2 +shortcut = SubResource("Shortcut_jj4yy") + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/TransformButtonsContainer/FlipVerticalButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +texture = ExtResource("4_2xhnr") +stretch_mode = 3 [node name="ModeButtonsContainer" type="HFlowContainer" parent="VBoxContainer"] layout_mode = 2 @@ -74,9 +152,10 @@ size_flags_horizontal = 3 size_flags_vertical = 3 [connection signal="toggled" from="VBoxContainer/PlaceTiles" to="." method="_on_place_tiles_toggled"] -[connection signal="toggled" from="VBoxContainer/TransformButtonsContainer/FlipHorizontalButton" to="." method="_on_flip_horizontal_button_toggled"] -[connection signal="toggled" from="VBoxContainer/TransformButtonsContainer/FlipVerticalButton" to="." method="_on_flip_vertical_button_toggled"] -[connection signal="toggled" from="VBoxContainer/TransformButtonsContainer/TransposeButton" to="." method="_on_transpose_button_toggled"] +[connection signal="pressed" from="VBoxContainer/TransformButtonsContainer/RotateLeftButton" to="." method="_on_rotate_pressed" binds= [false]] +[connection signal="pressed" from="VBoxContainer/TransformButtonsContainer/RotateRightButton" to="." method="_on_rotate_pressed" binds= [true]] +[connection signal="pressed" from="VBoxContainer/TransformButtonsContainer/FlipHorizontalButton" to="." method="_on_flip_horizontal_button_pressed"] +[connection signal="pressed" from="VBoxContainer/TransformButtonsContainer/FlipVerticalButton" to="." method="_on_flip_vertical_button_pressed"] [connection signal="toggled" from="VBoxContainer/ModeButtonsContainer/Manual" to="." method="_on_manual_toggled"] [connection signal="toggled" from="VBoxContainer/ModeButtonsContainer/Auto" to="." method="_on_auto_toggled"] [connection signal="toggled" from="VBoxContainer/ModeButtonsContainer/Stack" to="." method="_on_stack_toggled"]