mirror of
https://github.com/tonytins/citylimits.git
synced 2025-03-20 23:01:22 +00:00
714 lines
20 KiB
Text
714 lines
20 KiB
Text
[gd_scene load_steps=5 format=3 uid="uid://bf3b0i8scthbm"]
|
|
|
|
[ext_resource type="Texture2D" uid="uid://bnkl8rujlgv0h" path="res://addons/SpritesheetGenerator/Checker.png" id="1_hs1uu"]
|
|
|
|
[sub_resource type="GDScript" id="1"]
|
|
resource_name = "Generator"
|
|
script/source = "extends Control
|
|
|
|
const SUPPORTED_FORMATS: PackedStringArray = [\"bmp\", \"dds\", \"exr\", \"hdr\", \"jpg\", \"jpeg\", \"png\", \"tga\", \"svg\", \"svgz\", \"webp\"]
|
|
|
|
@onready var grid := %GridContainer
|
|
|
|
var file_list: Array
|
|
var image_list: Array
|
|
var texture_list: Array
|
|
|
|
var images_to_process: Array
|
|
var images_to_texturize: Array
|
|
var first_time := true
|
|
var image_count: int
|
|
var output_path: String
|
|
|
|
var auto := true
|
|
var margin := Vector2.ONE
|
|
|
|
var pan_origin: Vector2
|
|
var pan_start: Vector2
|
|
|
|
signal images_processed
|
|
|
|
func _enter_tree() -> void:
|
|
$SplitDialog.hide()
|
|
$StashDialog.hide()
|
|
|
|
func _ready():
|
|
$Status.text = $Status.text % \", \".join(SUPPORTED_FORMATS)
|
|
|
|
get_viewport().files_dropped.connect(load_files)
|
|
grid.minimum_size_changed.connect(refresh_background)
|
|
set_process(false)
|
|
|
|
func refresh_background():
|
|
%Background.custom_minimum_size = grid.get_minimum_size()
|
|
|
|
func load_files(files: PackedStringArray):
|
|
file_list.clear()
|
|
image_list.clear()
|
|
|
|
%CustomName.text = \"\"
|
|
%Reload.disabled = false
|
|
%SavePNG.disabled = false
|
|
|
|
if files.size() == 1 and not FileAccess.file_exists(files[0]):
|
|
var dir := DirAccess.open(files[0])
|
|
if not dir:
|
|
show_error(\"Can't open directory.\")
|
|
return
|
|
|
|
for file in dir.get_files():
|
|
if file.get_extension() in SUPPORTED_FORMATS:
|
|
file_list.append(str(dir.get_current_dir().path_join(file)))
|
|
else:
|
|
var wrong_count: int
|
|
for file in files:
|
|
if file.get_extension() in SUPPORTED_FORMATS:
|
|
file_list.append(file)
|
|
else:
|
|
wrong_count += 1
|
|
|
|
if wrong_count > 0:
|
|
show_error(\"Skipped %s file(s) with unsupported extension.\" % wrong_count)
|
|
|
|
if file_list.is_empty():
|
|
show_error(\"No valid files or directories to process.\")
|
|
return
|
|
|
|
load_images()
|
|
|
|
func load_images():
|
|
texture_list.clear()
|
|
|
|
for image in grid.get_children():
|
|
image.free()
|
|
|
|
for image in %StashImages.get_children():
|
|
image.free()
|
|
update_stash()
|
|
|
|
var size_map: Dictionary
|
|
|
|
if not file_list.is_empty():
|
|
image_list = file_list.map(func(file: String):
|
|
var image := Image.load_from_file(file)
|
|
if image:
|
|
image.set_meta(&\"path\", file)
|
|
return image)
|
|
|
|
for image in image_list:
|
|
if not image:
|
|
continue
|
|
|
|
if not image.get_size() in size_map:
|
|
size_map[image.get_size()] = []
|
|
size_map[image.get_size()].append(image)
|
|
|
|
var output_name: String
|
|
var most_common_size: Vector2i
|
|
var most_common_count: int
|
|
|
|
for size in size_map:
|
|
if size_map[size].size() > most_common_count:
|
|
most_common_size = size
|
|
most_common_count = size_map[size].size()
|
|
|
|
for image in size_map[most_common_size]:
|
|
if output_path.is_empty():
|
|
var path: String = image.get_meta(&\"path\", \"\")
|
|
output_path = path.get_base_dir()
|
|
output_name = path.get_base_dir().get_file()
|
|
|
|
images_to_process.append(image)
|
|
size_map.clear()
|
|
|
|
if not output_name.is_empty() and %CustomName.text.is_empty():
|
|
%CustomName.text = output_name
|
|
update_save_button()
|
|
|
|
if images_to_process.size() < file_list.size():
|
|
show_error(\"Rejected %s image(s) due to size mismatch.\" % (file_list.size() - images_to_process.size()))
|
|
|
|
if images_to_process.size() == 1:
|
|
if file_list.size() > 1:
|
|
images_to_process.clear()
|
|
show_error(\"Only one dropped image was valid.\")
|
|
else:
|
|
%SplitPreview.texture = ImageTexture.create_from_image(images_to_process[0])
|
|
$SplitDialog.reset_size()
|
|
$SplitDialog.popup_centered()
|
|
|
|
return
|
|
|
|
$Status.show()
|
|
%CenterContainer.hide()
|
|
|
|
image_count = images_to_process.size()
|
|
%Columns.max_value = image_count
|
|
|
|
threshold = %Threshold.value
|
|
min_x = 9999999
|
|
min_y = 9999999
|
|
max_x = -9999999
|
|
max_y = -9999999
|
|
|
|
set_process(true)
|
|
|
|
await images_processed
|
|
|
|
for texture in texture_list:
|
|
add_frame(texture)
|
|
|
|
toggle_auto(auto)
|
|
refresh_margin()
|
|
|
|
$Status.hide()
|
|
%CenterContainer.show()
|
|
|
|
var threshold: float
|
|
var min_x: int
|
|
var min_y: int
|
|
var max_x: int
|
|
var max_y: int
|
|
|
|
func _process(delta: float) -> void:
|
|
if not images_to_process.is_empty():
|
|
var image: Image = images_to_process.pop_front()
|
|
$Status.text = str(\"Preprocessing image \", image_count - images_to_process.size(), \"/\", image_count)
|
|
|
|
for x in image.get_width():
|
|
for y in image.get_height():
|
|
if image.get_pixel(x, y).a >= threshold:
|
|
min_x = mini(min_x, x)
|
|
min_y = mini(min_y, y)
|
|
max_x = maxi(max_x, x)
|
|
max_y = maxi(max_y, y)
|
|
|
|
images_to_texturize.append(image)
|
|
elif not images_to_texturize.is_empty():
|
|
var rect := Rect2i(min_x, min_y, max_x - min_x + 1, max_y - min_y + 1)
|
|
var image: Image = images_to_texturize.pop_front()
|
|
$Status.text = str(\"Creating texture \", image_count - images_to_texturize.size(), \"/\", image_count)
|
|
|
|
var true_image := Image.create(rect.size.x, rect.size.y, false, image.get_format())
|
|
true_image.blit_rect(image, rect, Vector2())
|
|
|
|
var texture := ImageTexture.create_from_image(true_image)
|
|
texture_list.append(texture)
|
|
|
|
if images_to_texturize.is_empty():
|
|
set_process(false)
|
|
images_processed.emit()
|
|
if first_time:
|
|
recenter()
|
|
first_time = false
|
|
|
|
func toggle_grid(show: bool) -> void:
|
|
get_tree().call_group(&\"frame\", &\"set_display_background\", show)
|
|
|
|
func toggle_auto(button_pressed: bool) -> void:
|
|
%Columns.editable = not button_pressed
|
|
auto = button_pressed
|
|
|
|
if button_pressed:
|
|
var best: int
|
|
var best_score = -9999999
|
|
|
|
for i in range(1, image_count + 1):
|
|
var cols = i
|
|
var rows = ceili(image_count / float(i))
|
|
|
|
var score = image_count - cols * rows - maxi(cols, rows) - rows
|
|
if score > best_score:
|
|
best = i
|
|
best_score = score
|
|
|
|
grid.columns = best
|
|
else:
|
|
grid.columns = %Columns.value
|
|
refresh_grid()
|
|
|
|
func hmargin_changed(value: float) -> void:
|
|
margin.x = value
|
|
refresh_margin()
|
|
|
|
func vmargin_changed(value: float) -> void:
|
|
margin.y = value
|
|
refresh_margin()
|
|
|
|
func refresh_margin():
|
|
get_tree().call_group(&\"frame\", &\"set_frame_margin\", margin)
|
|
|
|
func columns_changed(value: float) -> void:
|
|
grid.columns = value
|
|
refresh_grid()
|
|
|
|
func refresh_grid():
|
|
var coord: Vector2
|
|
var dark = false
|
|
|
|
for rect in grid.get_children():
|
|
rect.set_background_color(Color(0, 0, 0, 0.2 if dark else 0.1))
|
|
dark = not dark
|
|
coord.x += 1
|
|
|
|
if coord.x == grid.columns:
|
|
coord.x = 0
|
|
coord.y += 1
|
|
dark = int(coord.y) % 2 == 1
|
|
|
|
func save_png() -> void:
|
|
var image_size: Vector2 = grid.get_child(0).get_minimum_size()
|
|
|
|
var image := Image.create(image_size.x * grid.columns, image_size.y * (ceil(grid.get_child_count() / float(grid.columns))), false, Image.FORMAT_RGBA8)
|
|
|
|
for rect in grid.get_children():
|
|
image.blit_rect(rect.get_texture_data(), Rect2(Vector2(), image_size), rect.get_position2())
|
|
|
|
image.save_png(output_path.path_join(%CustomName.text) + \".png\")
|
|
|
|
func show_error(text: String):
|
|
if not %Error.visible:
|
|
%Error.show()
|
|
else:
|
|
%Error.text += \"\\n\"
|
|
%Error.text += text
|
|
%Timer.start()
|
|
|
|
func error_hidden() -> void:
|
|
%Error.text = \"\"
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if event is InputEventMouseButton:
|
|
var cc: Control = %CenterContainer
|
|
|
|
if event.button_index == MOUSE_BUTTON_MIDDLE:
|
|
if event.pressed:
|
|
pan_origin = get_local_mouse_position()
|
|
pan_start = cc.position
|
|
else:
|
|
pan_origin = Vector2()
|
|
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
|
|
var lm = cc.get_local_mouse_position()
|
|
cc.scale -= Vector2.ONE * 0.05
|
|
if cc.scale.x <= 0:
|
|
cc.scale = Vector2.ONE * 0.05
|
|
|
|
cc.position -= (lm - cc.get_local_mouse_position()) * cc.scale
|
|
elif event.button_index == MOUSE_BUTTON_WHEEL_UP:
|
|
var lm = cc.get_local_mouse_position()
|
|
cc.scale += Vector2.ONE * 0.05
|
|
cc.position -= (lm - cc.get_local_mouse_position()) * cc.scale
|
|
|
|
if event is InputEventMouseMotion:
|
|
if pan_origin != Vector2():
|
|
%CenterContainer.position = pan_start + (get_local_mouse_position() - pan_origin)
|
|
|
|
func recenter() -> void:
|
|
%CenterContainer.position = get_viewport().size / 2 - Vector2i(%CenterContainer.size) / 2
|
|
%CenterContainer.scale = Vector2.ONE
|
|
|
|
func update_split_preview():
|
|
%SplitPreview.queue_redraw()
|
|
|
|
func draw_split_preview() -> void:
|
|
var preview: TextureRect = %SplitPreview
|
|
var frame_count := Vector2(%SplitX.value, %SplitY.value)
|
|
var frame_size := preview.size / frame_count
|
|
|
|
for x in range(1, frame_count.x):
|
|
for y in int(frame_count.y):
|
|
preview.draw_line(frame_size * Vector2(x, y), frame_size * Vector2(x, y + 1), Color.WHITE)
|
|
preview.draw_line(frame_size * Vector2(x, y) + Vector2.RIGHT, frame_size * Vector2(x, y + 1) + Vector2.RIGHT, Color.BLACK)
|
|
|
|
for y in range(1, frame_count.y):
|
|
for x in int(frame_count.x):
|
|
preview.draw_line(frame_size * Vector2(x, y), frame_size * Vector2(x + 1, y), Color.WHITE)
|
|
preview.draw_line(frame_size * Vector2(x, y) + Vector2.DOWN, frame_size * Vector2(x + 1, y) + Vector2.DOWN, Color.BLACK)
|
|
|
|
func split_spritesheet() -> void:
|
|
file_list.clear()
|
|
image_list.clear()
|
|
|
|
var image: Image = images_to_process[0]
|
|
var sub_image_size := image.get_size() / Vector2i(%SplitX.value, %SplitY.value)
|
|
|
|
for y in %SplitY.value:
|
|
for x in %SplitX.value:
|
|
image_list.append(image.get_region(Rect2i(Vector2i(x, y) * sub_image_size, sub_image_size)))
|
|
|
|
images_to_process.clear()
|
|
load_images()
|
|
|
|
func remove_frame(frame):
|
|
var image: Image = frame.get_texture_data()
|
|
var texture := ImageTexture.create_from_image(image)
|
|
|
|
var button := TextureButton.new()
|
|
button.texture_normal = texture
|
|
button.custom_minimum_size = Vector2(128, 128)
|
|
button.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
|
button.ignore_texture_size = true
|
|
button.pressed.connect(re_add_image.bind(button), CONNECT_DEFERRED)
|
|
%StashImages.add_child(button)
|
|
|
|
var ref := ReferenceRect.new()
|
|
button.add_child(ref)
|
|
ref.set_anchors_and_offsets_preset(Control.PRESET_FULL_RECT)
|
|
ref.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
|
ref.editor_only = false
|
|
|
|
frame.free()
|
|
refresh_grid()
|
|
update_stash()
|
|
|
|
func update_stash():
|
|
%Stash.disabled = %StashImages.get_child_count() == 0
|
|
|
|
func re_add_image(tb: TextureButton):
|
|
add_frame(tb.texture_normal)
|
|
tb.free()
|
|
refresh_grid()
|
|
update_stash()
|
|
|
|
if %Stash.disabled:
|
|
$StashDialog.hide()
|
|
|
|
func add_frame(texture: Texture2D):
|
|
var rect := preload(\"res://addons/SpritesheetGenerator/SpritesheetFrame.tscn\").instantiate()
|
|
rect.set_texture(texture)
|
|
rect.set_display_background(%DisplayGrid.button_pressed)
|
|
rect.set_frame_margin(margin)
|
|
grid.add_child(rect)
|
|
|
|
func update_save_button() -> void:
|
|
%SavePNG.disabled = %CustomName.text.is_empty()
|
|
"
|
|
|
|
[sub_resource type="StyleBoxFlat" id="5"]
|
|
content_margin_left = 20.0
|
|
content_margin_top = 20.0
|
|
content_margin_right = 20.0
|
|
content_margin_bottom = 20.0
|
|
bg_color = Color(0, 0, 0, 0.25098)
|
|
|
|
[sub_resource type="StyleBoxTexture" id="StyleBoxTexture_kjgn5"]
|
|
texture = ExtResource("1_hs1uu")
|
|
axis_stretch_horizontal = 1
|
|
axis_stretch_vertical = 1
|
|
|
|
[node name="Main" type="HBoxContainer"]
|
|
anchors_preset = 15
|
|
anchor_right = 1.0
|
|
anchor_bottom = 1.0
|
|
grow_horizontal = 2
|
|
grow_vertical = 2
|
|
mouse_filter = 2
|
|
script = SubResource("1")
|
|
|
|
[node name="MarginContainer" type="PanelContainer" parent="."]
|
|
layout_mode = 2
|
|
theme_override_styles/panel = SubResource("5")
|
|
|
|
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
|
|
layout_mode = 2
|
|
theme_override_constants/separation = 10
|
|
|
|
[node name="Label5" type="Label" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Alpha Threshold"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="Threshold" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
max_value = 1.0
|
|
step = 0.005
|
|
value = 0.9
|
|
|
|
[node name="Reload" type="Button" parent="MarginContainer/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
disabled = true
|
|
text = "Reload"
|
|
|
|
[node name="HSeparator" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="Label" type="Label" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Columns"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="Columns" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
min_value = 1.0
|
|
value = 1.0
|
|
editable = false
|
|
|
|
[node name="Grid" type="CheckButton" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
button_pressed = true
|
|
text = "Auto"
|
|
|
|
[node name="Label3" type="Label" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Horizontal Margin"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="MarginH" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
value = 1.0
|
|
suffix = "px"
|
|
|
|
[node name="Label4" type="Label" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Vertical Margin"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="MarginV" type="SpinBox" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
max_value = 128.0
|
|
value = 1.0
|
|
suffix = "px"
|
|
|
|
[node name="Stash" type="Button" parent="MarginContainer/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
disabled = true
|
|
text = "Image Stash"
|
|
|
|
[node name="HSeparator2" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="Button" type="Button" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Recenter View
|
|
"
|
|
|
|
[node name="DisplayGrid" type="CheckBox" parent="MarginContainer/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
button_pressed = true
|
|
text = "Show Grid"
|
|
|
|
[node name="HSeparator3" type="HSeparator" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="CustomName" type="LineEdit" parent="MarginContainer/VBoxContainer/HBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
size_flags_horizontal = 3
|
|
placeholder_text = "Image Name"
|
|
|
|
[node name="SavePNG" type="Button" parent="MarginContainer/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
disabled = true
|
|
text = "Save PNG"
|
|
|
|
[node name="Status" type="Label" parent="."]
|
|
layout_mode = 2
|
|
size_flags_horizontal = 3
|
|
size_flags_vertical = 3
|
|
text = "Drop folder or image files here to start.
|
|
|
|
Images should be of the same size. If their sizes don't match, the generator will try to use the dominating size.
|
|
|
|
The images will be automatically cropped based on the Alpha Threshold value. Greater value means more exact crop.
|
|
|
|
Supported formats: %s
|
|
|
|
If you drop a single image, the generator will instead edit it as spritesheet."
|
|
horizontal_alignment = 1
|
|
vertical_alignment = 1
|
|
|
|
[node name="View" type="CanvasLayer" parent="."]
|
|
layer = -1
|
|
|
|
[node name="CenterContainer" type="CenterContainer" parent="View"]
|
|
unique_name_in_owner = true
|
|
visible = false
|
|
anchors_preset = 15
|
|
anchor_right = 1.0
|
|
anchor_bottom = 1.0
|
|
grow_horizontal = 2
|
|
grow_vertical = 2
|
|
size_flags_horizontal = 3
|
|
|
|
[node name="Background" type="ColorRect" parent="View/CenterContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
mouse_filter = 1
|
|
color = Color(0, 0.501961, 0.501961, 1)
|
|
|
|
[node name="GridContainer" type="GridContainer" parent="View/CenterContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
theme_override_constants/h_separation = 0
|
|
theme_override_constants/v_separation = 0
|
|
columns = 3
|
|
|
|
[node name="VBoxContainer" type="GridContainer" parent="View"]
|
|
anchors_preset = 3
|
|
anchor_left = 1.0
|
|
anchor_top = 1.0
|
|
anchor_right = 1.0
|
|
anchor_bottom = 1.0
|
|
offset_left = -40.0
|
|
offset_top = -40.0
|
|
grow_horizontal = 0
|
|
grow_vertical = 0
|
|
mouse_filter = 2
|
|
columns = 3
|
|
|
|
[node name="Label" type="Label" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "LMB"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="VSeparator" type="VSeparator" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="Label2" type="Label" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "rearrange images"
|
|
|
|
[node name="Label3" type="Label" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "RMB"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="VSeparator2" type="VSeparator" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="Label4" type="Label" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "delete images"
|
|
|
|
[node name="Label5" type="Label" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "MMB"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="VSeparator3" type="VSeparator" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
|
|
[node name="Label6" type="Label" parent="View/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "pan view"
|
|
|
|
[node name="CanvasLayer" type="CanvasLayer" parent="."]
|
|
|
|
[node name="Error" type="Label" parent="CanvasLayer"]
|
|
unique_name_in_owner = true
|
|
modulate = Color(1, 0, 0, 1)
|
|
anchors_preset = 12
|
|
anchor_top = 1.0
|
|
anchor_right = 1.0
|
|
anchor_bottom = 1.0
|
|
offset_top = -14.0
|
|
grow_horizontal = 2
|
|
grow_vertical = 0
|
|
size_flags_vertical = 0
|
|
horizontal_alignment = 1
|
|
|
|
[node name="Timer" type="Timer" parent="CanvasLayer"]
|
|
unique_name_in_owner = true
|
|
wait_time = 5.0
|
|
one_shot = true
|
|
|
|
[node name="SplitDialog" type="ConfirmationDialog" parent="."]
|
|
title = "Edit Spritesheet"
|
|
position = Vector2i(-500, 0)
|
|
size = Vector2i(272, 343)
|
|
visible = true
|
|
|
|
[node name="VBoxContainer" type="VBoxContainer" parent="SplitDialog"]
|
|
offset_left = 8.0
|
|
offset_top = 8.0
|
|
offset_right = 264.0
|
|
offset_bottom = 294.0
|
|
|
|
[node name="Label" type="Label" parent="SplitDialog/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Split Frames"
|
|
horizontal_alignment = 1
|
|
|
|
[node name="HBoxContainer" type="HBoxContainer" parent="SplitDialog/VBoxContainer"]
|
|
layout_mode = 2
|
|
alignment = 1
|
|
|
|
[node name="SplitX" type="SpinBox" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
min_value = 1.0
|
|
max_value = 1000.0
|
|
value = 1.0
|
|
select_all_on_focus = true
|
|
|
|
[node name="Label" type="Label" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
|
layout_mode = 2
|
|
text = "x"
|
|
|
|
[node name="SplitY" type="SpinBox" parent="SplitDialog/VBoxContainer/HBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
min_value = 1.0
|
|
max_value = 1000.0
|
|
value = 1.0
|
|
select_all_on_focus = true
|
|
|
|
[node name="CenterContainer" type="CenterContainer" parent="SplitDialog/VBoxContainer"]
|
|
layout_mode = 2
|
|
size_flags_vertical = 3
|
|
|
|
[node name="PanelContainer" type="PanelContainer" parent="SplitDialog/VBoxContainer/CenterContainer"]
|
|
layout_mode = 2
|
|
theme_override_styles/panel = SubResource("StyleBoxTexture_kjgn5")
|
|
|
|
[node name="SplitPreview" type="TextureRect" parent="SplitDialog/VBoxContainer/CenterContainer/PanelContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
|
|
[node name="StashDialog" type="AcceptDialog" parent="."]
|
|
title = "Image Stash"
|
|
position = Vector2i(-500, 500)
|
|
size = Vector2i(309, 100)
|
|
visible = true
|
|
|
|
[node name="VBoxContainer" type="VBoxContainer" parent="StashDialog"]
|
|
offset_left = 8.0
|
|
offset_top = 8.0
|
|
offset_right = 301.0
|
|
offset_bottom = 51.0
|
|
|
|
[node name="Label" type="Label" parent="StashDialog/VBoxContainer"]
|
|
layout_mode = 2
|
|
text = "Click frame to re-add it to spritesheet."
|
|
horizontal_alignment = 1
|
|
|
|
[node name="StashImages" type="HFlowContainer" parent="StashDialog/VBoxContainer"]
|
|
unique_name_in_owner = true
|
|
layout_mode = 2
|
|
|
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/Reload" to="." method="load_images"]
|
|
[connection signal="value_changed" from="MarginContainer/VBoxContainer/Columns" to="." method="columns_changed"]
|
|
[connection signal="toggled" from="MarginContainer/VBoxContainer/Grid" to="." method="toggle_auto"]
|
|
[connection signal="value_changed" from="MarginContainer/VBoxContainer/MarginH" to="." method="hmargin_changed"]
|
|
[connection signal="value_changed" from="MarginContainer/VBoxContainer/MarginV" to="." method="vmargin_changed"]
|
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/Stash" to="StashDialog" method="popup_centered_ratio" binds= [0.5]]
|
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/Button" to="." method="recenter"]
|
|
[connection signal="toggled" from="MarginContainer/VBoxContainer/DisplayGrid" to="." method="toggle_grid"]
|
|
[connection signal="text_changed" from="MarginContainer/VBoxContainer/HBoxContainer/CustomName" to="." method="update_save_button" unbinds=1]
|
|
[connection signal="pressed" from="MarginContainer/VBoxContainer/SavePNG" to="." method="save_png"]
|
|
[connection signal="hidden" from="CanvasLayer/Error" to="." method="error_hidden"]
|
|
[connection signal="timeout" from="CanvasLayer/Timer" to="CanvasLayer/Error" method="hide"]
|
|
[connection signal="confirmed" from="SplitDialog" to="." method="split_spritesheet"]
|
|
[connection signal="value_changed" from="SplitDialog/VBoxContainer/HBoxContainer/SplitX" to="." method="update_split_preview" unbinds=1]
|
|
[connection signal="value_changed" from="SplitDialog/VBoxContainer/HBoxContainer/SplitY" to="." method="update_split_preview" unbinds=1]
|
|
[connection signal="draw" from="SplitDialog/VBoxContainer/CenterContainer/PanelContainer/SplitPreview" to="." method="draw_split_preview"]
|