diff --git a/src/Autoload/HTML5FileExchange.gd b/src/Autoload/HTML5FileExchange.gd
index 00e361c53..3cbedf364 100644
--- a/src/Autoload/HTML5FileExchange.gd
+++ b/src/Autoload/HTML5FileExchange.gd
@@ -3,6 +3,7 @@ extends Node
# Thanks to Pukkah from GitHub for providing the original code
signal in_focus
+signal image_loaded # emits a signal for returning loaded image info
func _ready() -> void:
@@ -70,7 +71,9 @@ func _define_js() -> void:
)
-func load_image() -> void:
+# If (load_directly = false) then image info (image and it's name)
+# will not be directly farwarded it to OpenSave
+func load_image(load_directly := true):
if OS.get_name() != "HTML5" or !OS.has_feature("JavaScript"):
return
@@ -97,6 +100,7 @@ func load_image() -> void:
var image = Image.new()
var image_error
+ var image_info: Dictionary = {}
match image_type:
"image/png":
image_error = image.load_png_from_buffer(image_data)
@@ -111,7 +115,10 @@ func load_image() -> void:
print("An error occurred while trying to display the image.")
return
else:
- OpenSave.handle_loading_image(image_name, image)
+ image_info = {"image": image, "name": image_name}
+ if load_directly:
+ OpenSave.handle_loading_image(image_name, image)
+ emit_signal("image_loaded", image_info)
func load_shader() -> void:
diff --git a/src/Autoload/OpenSave.gd b/src/Autoload/OpenSave.gd
index 10e718eb9..7a554f0b7 100644
--- a/src/Autoload/OpenSave.gd
+++ b/src/Autoload/OpenSave.gd
@@ -125,6 +125,17 @@ func open_pxo_file(path: String, untitled_backup: bool = false, replace_empty: b
new_project.brushes.append(image)
Brushes.add_project_brush(image)
+ if dict.result.has("tile_mask") and dict.result.has("has_mask"):
+ if dict.result.has_mask:
+ var t_width = dict.result.tile_mask.size_x
+ var t_height = dict.result.tile_mask.size_y
+ var buffer := file.get_buffer(t_width * t_height * 4)
+ var image := Image.new()
+ image.create_from_data(t_width, t_height, false, Image.FORMAT_RGBA8, buffer)
+ new_project.tiles.tile_mask = image
+ else:
+ new_project.tiles.reset_mask()
+
file.close()
if !empty_project:
Global.projects.append(new_project)
@@ -351,6 +362,9 @@ func save_pxo_file(
for brush in project.brushes:
file.store_buffer(brush.get_data())
+ if project.tiles.has_mask:
+ file.store_buffer(project.tiles.tile_mask.get_data())
+
file.close()
if OS.get_name() == "HTML5" and OS.has_feature("JavaScript") and !autosave:
diff --git a/src/Classes/Project.gd b/src/Classes/Project.gd
index 4f08ad519..8bfb2c800 100644
--- a/src/Classes/Project.gd
+++ b/src/Classes/Project.gd
@@ -347,6 +347,10 @@ func serialize() -> Dictionary:
for brush in brushes:
brush_data.append({"size_x": brush.get_size().x, "size_y": brush.get_size().y})
+ var tile_mask_data := {
+ "size_x": tiles.tile_mask.get_size().x, "size_y": tiles.tile_mask.get_size().y
+ }
+
var metadata := _serialize_metadata(self)
var project_data := {
@@ -354,6 +358,8 @@ func serialize() -> Dictionary:
"name": name,
"size_x": size.x,
"size_y": size.y,
+ "has_mask": tiles.has_mask,
+ "tile_mask": tile_mask_data,
"tile_mode_x_basis_x": tiles.x_basis.x,
"tile_mode_x_basis_y": tiles.x_basis.y,
"tile_mode_y_basis_x": tiles.y_basis.x,
@@ -383,6 +389,8 @@ func deserialize(dict: Dictionary) -> void:
size.y = dict.size_y
tiles.tile_size = size
selection_bitmap = resize_bitmap(selection_bitmap, size)
+ if dict.has("has_mask"):
+ tiles.has_mask = dict.has_mask
if dict.has("tile_mode_x_basis_x") and dict.has("tile_mode_x_basis_y"):
tiles.x_basis.x = dict.tile_mode_x_basis_x
tiles.x_basis.y = dict.tile_mode_x_basis_y
@@ -494,6 +502,7 @@ func _size_changed(value: Vector2) -> void:
else:
tiles.y_basis = Vector2(0, value.y)
tiles.tile_size = value
+ tiles.reset_mask()
size = value
@@ -760,7 +769,7 @@ func can_pixel_get_drawn(
if pixel.x < 0 or pixel.y < 0 or pixel.x >= size.x or pixel.y >= size.y:
return false
- if tiles.mode != Tiles.MODE.NONE and tiles.get_nearest_tile(pixel).position != Vector2.ZERO:
+ if tiles.mode != Tiles.MODE.NONE and !tiles.has_point(pixel):
return false
if has_selection:
diff --git a/src/Classes/Tiles.gd b/src/Classes/Tiles.gd
index 564bc2c72..61779be80 100644
--- a/src/Classes/Tiles.gd
+++ b/src/Classes/Tiles.gd
@@ -7,12 +7,16 @@ var mode: int = MODE.NONE
var x_basis: Vector2
var y_basis: Vector2
var tile_size: Vector2
+var tile_mask := Image.new()
+var has_mask := false
func _init(size: Vector2):
x_basis = Vector2(size.x, 0)
y_basis = Vector2(0, size.y)
tile_size = size
+ tile_mask.create(tile_size.x, tile_size.y, false, Image.FORMAT_RGBA8)
+ tile_mask.fill(Color.white)
func get_bounding_rect() -> Rect2:
@@ -41,29 +45,36 @@ func get_bounding_rect() -> Rect2:
func get_nearest_tile(point: Vector2) -> Rect2:
- var tile_to_screen_space := Transform2D(x_basis, y_basis, Vector2.ZERO)
- # Transform2D.basis_xform_inv() is broken so compute the inverse explicitly:
- # https://github.com/godotengine/godot/issues/58556
- var screen_to_tile_space := tile_to_screen_space.affine_inverse()
- var p := point - tile_size / 2.0 + Vector2(0.5, 0.5) # p relative to center of tiles
- var p_tile_space := screen_to_tile_space.basis_xform(p)
- var tl_tile := tile_to_screen_space.basis_xform(p_tile_space.floor())
- var tr_tile := tl_tile + x_basis
- var bl_tile := tl_tile + y_basis
- var br_tile := tl_tile + x_basis + y_basis
- var tl_tile_dist := (p - tl_tile).length_squared()
- var tr_tile_dist := (p - tr_tile).length_squared()
- var bl_tile_dist := (p - bl_tile).length_squared()
- var br_tile_dist := (p - br_tile).length_squared()
- match [tl_tile_dist, tr_tile_dist, bl_tile_dist, br_tile_dist].min():
- tl_tile_dist:
- return Rect2(tl_tile, tile_size)
- tr_tile_dist:
- return Rect2(tr_tile, tile_size)
- bl_tile_dist:
- return Rect2(bl_tile, tile_size)
- _:
- return Rect2(br_tile, tile_size)
+ var positions = Global.canvas.tile_mode.get_tile_positions()
+ positions.append(Vector2.ZERO)
+
+ var candidates := []
+ for pos in positions:
+ var test_rect = Rect2(pos, tile_size)
+ if test_rect.has_point(point):
+ candidates.append(test_rect)
+ if candidates.empty():
+ return Rect2(Vector2.ZERO, tile_size)
+
+ var final := []
+ tile_mask.lock()
+ for candidate in candidates:
+ var rel_pos = point - candidate.position
+ if tile_mask.get_pixelv(rel_pos).a == 1.0:
+ final.append(candidate)
+ tile_mask.unlock()
+
+ if final.empty():
+ return Rect2(Vector2.ZERO, tile_size)
+ final.sort_custom(self, "sort_by_height")
+ return final[0]
+
+
+func sort_by_height(a: Rect2, b: Rect2):
+ if a.position.y > b.position.y:
+ return false
+ else:
+ return true
func get_canon_position(position: Vector2) -> Vector2:
@@ -76,15 +87,19 @@ func get_canon_position(position: Vector2) -> Vector2:
func has_point(point: Vector2) -> bool:
- var screen_to_tile_space := Transform2D(x_basis, y_basis, Vector2.ZERO).affine_inverse()
- var nearest_tile := get_nearest_tile(point)
- var nearest_tile_tile_space := screen_to_tile_space.basis_xform(nearest_tile.position).round()
- match mode:
- MODE.BOTH:
- return abs(nearest_tile_tile_space.x) <= 1 and abs(nearest_tile_tile_space.y) <= 1
- MODE.X_AXIS:
- return abs(nearest_tile_tile_space.x) <= 1 and abs(nearest_tile_tile_space.y) == 0
- MODE.Y_AXIS:
- return abs(nearest_tile_tile_space.x) == 0 and abs(nearest_tile_tile_space.y) <= 1
- _:
- return nearest_tile_tile_space == Vector2.ZERO
+ var positions = Global.canvas.tile_mode.get_tile_positions()
+ positions.append(Vector2.ZERO) # The central tile is included manually
+ tile_mask.lock()
+ for tile_pos in positions:
+ var test_rect = Rect2(tile_pos, tile_size)
+ var rel_pos = point - tile_pos
+ if test_rect.has_point(point) and tile_mask.get_pixelv(rel_pos).a == 1.0:
+ return true
+ tile_mask.unlock()
+ return false
+
+
+func reset_mask():
+ tile_mask.create(tile_size.x, tile_size.y, false, Image.FORMAT_RGBA8)
+ tile_mask.fill(Color.white)
+ has_mask = false
diff --git a/src/Tools/Bucket.gd b/src/Tools/Bucket.gd
index a762a820c..4f799fc0e 100644
--- a/src/Tools/Bucket.gd
+++ b/src/Tools/Bucket.gd
@@ -145,7 +145,7 @@ func draw_start(position: Vector2) -> void:
Global.canvas.selection.transform_content_confirm()
if (
!Global.current_project.layers[Global.current_project.current_layer].can_layer_get_drawn()
- or Global.current_project.tiles.get_nearest_tile(position).position != Vector2.ZERO
+ or !Rect2(Vector2.ZERO, Global.current_project.size).has_point(position)
):
return
if (
diff --git a/src/UI/Canvas/Canvas.tscn b/src/UI/Canvas/Canvas.tscn
index 92d2162ec..37a2127fd 100644
--- a/src/UI/Canvas/Canvas.tscn
+++ b/src/UI/Canvas/Canvas.tscn
@@ -43,6 +43,7 @@ render_target_update_mode = 3
script = ExtResource( 5 )
[node name="TileMode" type="Node2D" parent="."]
+show_behind_parent = true
material = SubResource( 1 )
script = ExtResource( 4 )
diff --git a/src/UI/Dialogs/TileModeOffsetsDialog.gd b/src/UI/Dialogs/TileModeOffsetsDialog.gd
index ccc14ea21..633ed37d8 100644
--- a/src/UI/Dialogs/TileModeOffsetsDialog.gd
+++ b/src/UI/Dialogs/TileModeOffsetsDialog.gd
@@ -1,26 +1,62 @@
extends ConfirmationDialog
-onready var x_basis_x_spinbox: SpinBox = $VBoxContainer/OptionsContainer/XBasisX
-onready var x_basis_y_spinbox: SpinBox = $VBoxContainer/OptionsContainer/XBasisY
-onready var y_basis_x_spinbox: SpinBox = $VBoxContainer/OptionsContainer/YBasisX
-onready var y_basis_y_spinbox: SpinBox = $VBoxContainer/OptionsContainer/YBasisY
+onready var x_basis_x_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/XBasisX
+onready var x_basis_y_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/XBasisY
+onready var y_basis_x_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/YBasisX
+onready var y_basis_y_spinbox: SpinBox = $VBoxContainer/HBoxContainer/OptionsContainer/YBasisY
onready var preview_rect: Control = $VBoxContainer/AspectRatioContainer/Preview
onready var tile_mode: Node2D = $VBoxContainer/AspectRatioContainer/Preview/TileMode
+onready var load_button: Button = $VBoxContainer/HBoxContainer/Mask/LoadMask
+onready var mask_hint: TextureRect = $VBoxContainer/HBoxContainer/Mask/MaskHint
func _on_TileModeOffsetsDialog_about_to_show() -> void:
tile_mode.draw_center = true
tile_mode.tiles = Tiles.new(Global.current_project.size)
tile_mode.tiles.mode = Tiles.MODE.BOTH
+ if Global.current_project.tiles.mode != Tiles.MODE.NONE:
+ tile_mode.tiles.mode = Global.current_project.tiles.mode
+ if Global.current_project.tiles.mode != Tiles.MODE.NONE:
+ tile_mode.tiles.mode = Global.current_project.tiles.mode
tile_mode.tiles.x_basis = Global.current_project.tiles.x_basis
tile_mode.tiles.y_basis = Global.current_project.tiles.y_basis
x_basis_x_spinbox.value = tile_mode.tiles.x_basis.x
x_basis_y_spinbox.value = tile_mode.tiles.x_basis.y
y_basis_x_spinbox.value = tile_mode.tiles.y_basis.x
y_basis_y_spinbox.value = tile_mode.tiles.y_basis.y
+
+ _show_options()
+ if Global.current_project.tiles.mode == Tiles.MODE.X_AXIS:
+ y_basis_x_spinbox.visible = false
+ y_basis_y_spinbox.visible = false
+ $VBoxContainer/HBoxContainer/OptionsContainer/YBasisXLabel.visible = false
+ $VBoxContainer/HBoxContainer/OptionsContainer/YBasisYLabel.visible = false
+ elif Global.current_project.tiles.mode == Tiles.MODE.Y_AXIS:
+ x_basis_x_spinbox.visible = false
+ x_basis_y_spinbox.visible = false
+ $VBoxContainer/HBoxContainer/OptionsContainer/XBasisXLabel.visible = false
+ $VBoxContainer/HBoxContainer/OptionsContainer/XBasisYLabel.visible = false
+
+ load_button.text = "Load Mask"
+ if Global.current_project.tiles.has_mask:
+ load_button.text = "Loaded"
+ var tex := ImageTexture.new()
+ tex.create_from_image(Global.current_project.tiles.tile_mask)
+ mask_hint.texture = tex
update_preview()
+func _show_options():
+ x_basis_x_spinbox.visible = true
+ x_basis_y_spinbox.visible = true
+ y_basis_x_spinbox.visible = true
+ y_basis_y_spinbox.visible = true
+ $VBoxContainer/HBoxContainer/OptionsContainer/YBasisXLabel.visible = true
+ $VBoxContainer/HBoxContainer/OptionsContainer/YBasisYLabel.visible = true
+ $VBoxContainer/HBoxContainer/OptionsContainer/XBasisXLabel.visible = true
+ $VBoxContainer/HBoxContainer/OptionsContainer/XBasisYLabel.visible = true
+
+
func _on_TileModeOffsetsDialog_confirmed() -> void:
Global.current_project.tiles.x_basis = tile_mode.tiles.x_basis
Global.current_project.tiles.y_basis = tile_mode.tiles.y_basis
@@ -81,3 +117,47 @@ func _on_Reset_pressed():
y_basis_x_spinbox.value = 0
y_basis_y_spinbox.value = size.y
update_preview()
+
+
+func _on_LoadMask_pressed() -> void:
+ if OS.get_name() == "HTML5":
+ Html5FileExchange.connect("image_loaded", self, "_on_html_image_loaded")
+ Html5FileExchange.load_image(false)
+ else:
+ $FileDialog.current_dir = Global.current_project.directory_path
+ $FileDialog.popup_centered()
+
+
+func _on_html_image_loaded(image_info: Dictionary):
+ if image_info.has("image"):
+ load_mask(image_info.image)
+ Html5FileExchange.disconnect("image_loaded", self, "_on_html_image_loaded")
+
+
+func _on_FileDialog_file_selected(path: String) -> void:
+ var image := Image.new()
+ var err := image.load(path)
+ if err != OK: # An error occured
+ var file_name: String = path.get_file()
+ Global.error_dialog.set_text(
+ tr("Can't load file '%s'.\nError code: %s") % [file_name, str(err)]
+ )
+ Global.error_dialog.popup_centered()
+ Global.dialog_open(true)
+ return
+ if image.get_size() != Global.current_project.size:
+ Global.error_dialog.set_text(tr("The mask must have the same size as the project"))
+ Global.error_dialog.popup_centered()
+ Global.dialog_open(true)
+ return
+
+ load_mask(image)
+
+
+func load_mask(image: Image):
+ load_button.text = "Loaded"
+ Global.current_project.tiles.tile_mask = image
+ Global.current_project.tiles.has_mask = true
+ var tex := ImageTexture.new()
+ tex.create_from_image(Global.current_project.tiles.tile_mask)
+ mask_hint.texture = tex
diff --git a/src/UI/Dialogs/TileModeOffsetsDialog.tscn b/src/UI/Dialogs/TileModeOffsetsDialog.tscn
index 71d3d46b0..9277456a2 100644
--- a/src/UI/Dialogs/TileModeOffsetsDialog.tscn
+++ b/src/UI/Dialogs/TileModeOffsetsDialog.tscn
@@ -18,29 +18,33 @@ script = ExtResource( 3 )
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 8.0
margin_top = 8.0
-margin_right = 208.0
+margin_right = 293.0
margin_bottom = 362.0
[node name="TileModeOffsets" type="Label" parent="VBoxContainer"]
-margin_right = 200.0
+margin_right = 285.0
margin_bottom = 14.0
text = "Tile Mode Offsets"
-[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"]
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 18.0
-margin_right = 200.0
+margin_right = 285.0
margin_bottom = 150.0
+
+[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer/HBoxContainer"]
+margin_right = 137.0
+margin_bottom = 132.0
custom_constants/vseparation = 4
custom_constants/hseparation = 2
columns = 2
-[node name="XBasisXLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
+[node name="XBasisXLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_top = 5.0
margin_right = 61.0
margin_bottom = 19.0
text = "X-basis x:"
-[node name="XBasisX" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
+[node name="XBasisX" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_left = 63.0
margin_right = 137.0
margin_bottom = 24.0
@@ -49,13 +53,13 @@ min_value = -16384.0
max_value = 16384.0
suffix = "px"
-[node name="XBasisYLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
+[node name="XBasisYLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_top = 33.0
margin_right = 61.0
margin_bottom = 47.0
text = "X-basis y:"
-[node name="XBasisY" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
+[node name="XBasisY" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_left = 63.0
margin_top = 28.0
margin_right = 137.0
@@ -65,13 +69,13 @@ min_value = -16384.0
max_value = 16384.0
suffix = "px"
-[node name="YBasisXLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
+[node name="YBasisXLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_top = 61.0
margin_right = 61.0
margin_bottom = 75.0
text = "Y-basis x:"
-[node name="YBasisX" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
+[node name="YBasisX" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_left = 63.0
margin_top = 56.0
margin_right = 137.0
@@ -81,13 +85,13 @@ min_value = -16384.0
max_value = 16384.0
suffix = "px"
-[node name="YBasisYLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
+[node name="YBasisYLabel" type="Label" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_top = 89.0
margin_right = 61.0
margin_bottom = 103.0
text = "Y-basis y:"
-[node name="YBasisY" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
+[node name="YBasisY" type="SpinBox" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_left = 63.0
margin_top = 84.0
margin_right = 137.0
@@ -97,20 +101,67 @@ min_value = -16384.0
max_value = 16384.0
suffix = "px"
-[node name="Reset" type="Button" parent="VBoxContainer/OptionsContainer"]
+[node name="Reset" type="Button" parent="VBoxContainer/HBoxContainer/OptionsContainer"]
margin_top = 112.0
margin_right = 61.0
margin_bottom = 132.0
text = "Reset"
+[node name="VSeparator" type="VSeparator" parent="VBoxContainer/HBoxContainer"]
+margin_left = 141.0
+margin_right = 145.0
+margin_bottom = 132.0
+
+[node name="Mask" type="VBoxContainer" parent="VBoxContainer/HBoxContainer"]
+margin_left = 149.0
+margin_right = 285.0
+margin_bottom = 132.0
+size_flags_horizontal = 3
+
+[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/Mask"]
+margin_right = 136.0
+margin_bottom = 14.0
+text = "Tile Mask"
+align = 1
+
+[node name="HSeparator" type="HSeparator" parent="VBoxContainer/HBoxContainer/Mask"]
+margin_top = 18.0
+margin_right = 136.0
+margin_bottom = 22.0
+
+[node name="MaskHint" type="TextureRect" parent="VBoxContainer/HBoxContainer/Mask"]
+margin_top = 26.0
+margin_right = 136.0
+margin_bottom = 100.0
+rect_min_size = Vector2( 136, 74 )
+size_flags_vertical = 3
+expand = true
+stretch_mode = 6
+
+[node name="HSeparator2" type="HSeparator" parent="VBoxContainer/HBoxContainer/Mask"]
+margin_top = 104.0
+margin_right = 136.0
+margin_bottom = 108.0
+
+[node name="LoadMask" type="Button" parent="VBoxContainer/HBoxContainer/Mask"]
+margin_top = 112.0
+margin_right = 136.0
+margin_bottom = 132.0
+rect_min_size = Vector2( 100, 0 )
+hint_tooltip = "Mask will only allow the drawing to remain within it's bounds
+(Used for custom tiles)"
+text = "Load Mask"
+clip_text = true
+
[node name="AspectRatioContainer" type="AspectRatioContainer" parent="VBoxContainer"]
margin_top = 154.0
-margin_right = 200.0
+margin_right = 285.0
margin_bottom = 354.0
size_flags_vertical = 3
[node name="Preview" type="Control" parent="VBoxContainer/AspectRatioContainer"]
-margin_right = 200.0
+margin_left = 42.5
+margin_right = 242.5
margin_bottom = 200.0
rect_min_size = Vector2( 200, 200 )
@@ -125,12 +176,31 @@ anchor_bottom = 1.0
margin_right = 0.0
margin_bottom = 0.0
+[node name="FileDialog" type="FileDialog" parent="."]
+margin_left = 8.0
+margin_top = 8.0
+margin_right = 293.0
+margin_bottom = 362.0
+rect_min_size = Vector2( 172, 60.2 )
+window_title = "Open a File"
+resizable = true
+mode = 0
+access = 2
+filters = PoolStringArray( "*.png ; PNG Image" )
+current_dir = "/home/variable/Documents/Godot/Godot projects/Pixelorama-Tile-mode-Fixes"
+current_path = "/home/variable/Documents/Godot/Godot projects/Pixelorama-Tile-mode-Fixes/"
+__meta__ = {
+"_editor_description_": ""
+}
+
[connection signal="about_to_show" from="." to="." method="_on_TileModeOffsetsDialog_about_to_show"]
[connection signal="confirmed" from="." to="." method="_on_TileModeOffsetsDialog_confirmed"]
[connection signal="item_rect_changed" from="." to="." method="_on_TileModeOffsetsDialog_item_rect_changed"]
[connection signal="popup_hide" from="." to="." method="_on_TileModeOffsetsDialog_popup_hide"]
-[connection signal="value_changed" from="VBoxContainer/OptionsContainer/XBasisX" to="." method="_on_XBasisX_value_changed"]
-[connection signal="value_changed" from="VBoxContainer/OptionsContainer/XBasisY" to="." method="_on_XBasisY_value_changed"]
-[connection signal="value_changed" from="VBoxContainer/OptionsContainer/YBasisX" to="." method="_on_YBasisX_value_changed"]
-[connection signal="value_changed" from="VBoxContainer/OptionsContainer/YBasisY" to="." method="_on_YBasisY_value_changed"]
-[connection signal="pressed" from="VBoxContainer/OptionsContainer/Reset" to="." method="_on_Reset_pressed"]
+[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/XBasisX" to="." method="_on_XBasisX_value_changed"]
+[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/XBasisY" to="." method="_on_XBasisY_value_changed"]
+[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/YBasisX" to="." method="_on_YBasisX_value_changed"]
+[connection signal="value_changed" from="VBoxContainer/HBoxContainer/OptionsContainer/YBasisY" to="." method="_on_YBasisY_value_changed"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/OptionsContainer/Reset" to="." method="_on_Reset_pressed"]
+[connection signal="pressed" from="VBoxContainer/HBoxContainer/Mask/LoadMask" to="." method="_on_LoadMask_pressed"]
+[connection signal="file_selected" from="FileDialog" to="." method="_on_FileDialog_file_selected"]