Created a "UI" folder in src

And a Timeline folder in UI
This commit is contained in:
OverloadedOrama 2020-05-02 01:19:01 +03:00
parent 8d5a673543
commit c35e4b0613
51 changed files with 1444 additions and 1443 deletions

108
src/UI/BrushButton.gd Normal file
View file

@ -0,0 +1,108 @@
extends BaseButton
signal brush_selected
export var brush_type = 0 # Global.Brush_Types.PIXEL
export var custom_brush_index := -3
var random_brushes := []
func _on_BrushButton_pressed() -> void:
# Delete the brush on middle mouse press
if Input.is_action_just_released("middle_mouse"):
_on_DeleteButton_pressed()
return
# Change left brush
if Global.brush_type_window_position == "left":
Global.current_left_brush_type = brush_type
Global.custom_left_brush_index = custom_brush_index
if custom_brush_index > -1: # Custom brush
if Global.current_left_tool == "Pencil":
Global.left_color_interpolation_container.visible = true
# if hint_tooltip == "":
# Global.left_brush_type_label.text = tr("Custom brush")
# else:
# Global.left_brush_type_label.text = tr("Brush:") + " %s" % hint_tooltip
elif custom_brush_index == -3: # Pixel brush
Global.left_color_interpolation_container.visible = false
# Global.left_brush_type_label.text = tr("Brush: Pixel")
elif custom_brush_index == -2: # Circle brush
Global.left_color_interpolation_container.visible = false
# Global.left_brush_type_label.text = tr("Brush: Circle")
elif custom_brush_index == -1: # Filled Circle brush
Global.left_color_interpolation_container.visible = false
# Global.left_brush_type_label.text = tr("Brush: Filled Circle")
Global.update_left_custom_brush()
emit_signal("brush_selected")
else: # Change right brush
Global.current_right_brush_type = brush_type
Global.custom_right_brush_index = custom_brush_index
if custom_brush_index > -1:
if Global.current_right_tool == "Pencil":
Global.right_color_interpolation_container.visible = true
# if hint_tooltip == "":
# Global.right_brush_type_label.text = tr("Custom brush")
# else:
# Global.right_brush_type_label.text = tr("Brush:") + " %s" % hint_tooltip
elif custom_brush_index == -3: # Pixel brush
Global.right_color_interpolation_container.visible = false
# Global.right_brush_type_label.text = tr("Brush: Pixel")
elif custom_brush_index == -2: # Circle brush
Global.right_color_interpolation_container.visible = false
# Global.right_brush_type_label.text = tr("Brush: Circle")
elif custom_brush_index == -1: # Filled Circle brush
Global.right_color_interpolation_container.visible = false
# Global.right_brush_type_label.text = tr("Brush: Filled Circle")
Global.update_right_custom_brush()
emit_signal("brush_selected")
func _on_DeleteButton_pressed() -> void:
if brush_type == Global.Brush_Types.CUSTOM:
if Global.custom_left_brush_index == custom_brush_index:
Global.custom_left_brush_index = -3
Global.current_left_brush_type = Global.Brush_Types.PIXEL
# Global.left_brush_type_label.text = "Brush: Pixel"
Global.update_left_custom_brush()
if Global.custom_right_brush_index == custom_brush_index:
Global.custom_right_brush_index = -3
Global.current_right_brush_type = Global.Brush_Types.PIXEL
# Global.right_brush_type_label.text = "Brush: Pixel"
Global.update_right_custom_brush()
var project_brush_index = custom_brush_index - Global.brushes_from_files
Global.undos += 1
Global.undo_redo.create_action("Delete Custom Brush")
for i in range(project_brush_index, Global.project_brush_container.get_child_count()):
var bb = Global.project_brush_container.get_child(i)
if Global.custom_left_brush_index == bb.custom_brush_index:
Global.custom_left_brush_index -= 1
if Global.custom_right_brush_index == bb.custom_brush_index:
Global.custom_right_brush_index -= 1
Global.undo_redo.add_do_property(bb, "custom_brush_index", bb.custom_brush_index - 1)
Global.undo_redo.add_undo_property(bb, "custom_brush_index", bb.custom_brush_index)
var custom_brushes: Array = Global.custom_brushes.duplicate()
custom_brushes.remove(custom_brush_index)
Global.undo_redo.add_do_property(Global, "custom_brushes", custom_brushes)
Global.undo_redo.add_undo_property(Global, "custom_brushes", Global.custom_brushes)
Global.undo_redo.add_do_method(Global, "redo_custom_brush", self)
Global.undo_redo.add_undo_method(Global, "undo_custom_brush", self)
Global.undo_redo.commit_action()
func _on_BrushButton_mouse_entered() -> void:
if brush_type == Global.Brush_Types.CUSTOM:
$DeleteButton.visible = true
func _on_BrushButton_mouse_exited() -> void:
if brush_type == Global.Brush_Types.CUSTOM:
$DeleteButton.visible = false

59
src/UI/BrushButton.tscn Normal file

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,122 @@
extends WindowDialog
onready var credits = $AboutUI/Credits
onready var groups : Tree = $AboutUI/Credits/Groups
onready var developer_container = $AboutUI/Credits/Developers
onready var contributors_container = $AboutUI/Credits/Contributors
onready var donors_container = $AboutUI/Credits/Donors
onready var translators_container = $AboutUI/Credits/Translators
onready var developers : Tree = $AboutUI/Credits/Developers/DeveloperTree
onready var contributors : Tree = $AboutUI/Credits/Contributors/ContributorTree
onready var donors : Tree = $AboutUI/Credits/Donors/DonorTree
onready var translators : Tree = $AboutUI/Credits/Translators/TranslatorTree
func _ready() -> void:
var contributor_root := contributors.create_item()
contributors.create_item(contributor_root).set_text(0, " Hugo Locurcio (Calinou)")
contributors.create_item(contributor_root).set_text(0, " CheetoHead (greusser)")
contributors.create_item(contributor_root).set_text(0, " Michael Alexsander (YeldhamDev)")
contributors.create_item(contributor_root).set_text(0, " Schweini07")
contributors.create_item(contributor_root).set_text(0, " Martin Zabinski")
contributors.create_item(contributor_root).set_text(0, " azagaya")
contributors.create_item(contributor_root).set_text(0, " Andreev Andrei")
contributors.create_item(contributor_root).set_text(0, " Martin Novák (novhack)")
contributors.create_item(contributor_root).set_text(0, " Marco Galli (Gaarco)")
contributors.create_item(contributor_root).set_text(0, " Subhang Nanduri (SbNanduri)")
contributors.create_item(contributor_root).set_text(0, " danielnaoexiste")
contributors.create_item(contributor_root).set_text(0, " Noah Burck (haonkrub)")
contributors.create_item(contributor_root).set_text(0, " Darshan Phaldesai (luiq54)")
contributors.create_item(contributor_root).set_text(0, " Matheus Pesegoginski (MatheusPese)")
contributors.create_item(contributor_root).set_text(0, " sapient_cogbag")
contributors.create_item(contributor_root).set_text(0, " Kinwailo")
contributors.create_item(contributor_root).set_text(0, " Igor Santarek (jegor377)")
contributors.create_item(contributor_root).set_text(0, " Dávid Gábor BODOR (dragonfi)")
var donors_root := donors.create_item()
donors.create_item(donors_root).set_text(0, " pcmxms")
donors.create_item(donors_root).set_text(0, " Mike King")
func _on_AboutDialog_about_to_show() -> void:
var current_version : String = ProjectSettings.get_setting("application/config/Version")
window_title = tr("About Pixelorama") + " " + current_version
var groups_root := groups.create_item()
var developers_button := groups.create_item(groups_root)
var contributors_button := groups.create_item(groups_root)
var donors_button := groups.create_item(groups_root)
var translators_button := groups.create_item(groups_root)
developers_button.set_text(0, " " + tr("Developers"))
# We use metadata to avoid being affected by translations
developers_button.set_metadata(0, "Developers")
developers_button.select(0)
contributors_button.set_text(0, " " + tr("Contributors"))
contributors_button.set_metadata(0, "Contributors")
donors_button.set_text(0, " " + tr("Donors"))
donors_button.set_metadata(0, "Donors")
translators_button.set_text(0, " " + tr("Translators"))
translators_button.set_metadata(0, "Translators")
var dev_root := developers.create_item()
developers.create_item(dev_root).set_text(0, " Manolis Papadeas (Overloaded) - " + tr("Lead Programmer"))
developers.create_item(dev_root).set_text(0, " John Nikitakis (Erevos) - " + tr("UI Designer"))
# Translators
var translators_root := translators.create_item()
translators.create_item(translators_root).set_text(0, " Manolis Papadeas (Overloaded) - " + tr("Greek"))
translators.create_item(translators_root).set_text(0, " Xenofon Konitsas (huskee) - " + tr("Greek"))
translators.create_item(translators_root).set_text(0, " Hugo Locurcio (Calinou) - " + tr("French"))
translators.create_item(translators_root).set_text(0, " blackjoker77777 - " + tr("French"))
translators.create_item(translators_root).set_text(0, " Schweini07 - " + tr("German"))
translators.create_item(translators_root).set_text(0, " Martin Zabinski (Martin1991zab) - " + tr("German"))
translators.create_item(translators_root).set_text(0, " Dawid Niedźwiedzki (tiritto) - " + tr("Polish"))
translators.create_item(translators_root).set_text(0, " Serhiy Dmytryshyn (dies) - " + tr("Polish"))
translators.create_item(translators_root).set_text(0, " Michael Alexsander (YeldhamDev) - " + tr("Brazilian Portuguese"))
translators.create_item(translators_root).set_text(0, " Cedulio Cezar (ceduliocezar) - " + tr("Brazilian Portuguese"))
translators.create_item(translators_root).set_text(0, " Andreev Andrei - " + tr("Russian"))
translators.create_item(translators_root).set_text(0, " ax trifonov (ax34) - " + tr("Russian"))
translators.create_item(translators_root).set_text(0, " Artem (blinovartem) - " + tr("Russian"))
translators.create_item(translators_root).set_text(0, " JunYouIntrovert - " + tr("Chinese Traditional"))
translators.create_item(translators_root).set_text(0, " Chenxu Wang - " + tr("Chinese Simplified"))
translators.create_item(translators_root).set_text(0, " Marco Galli (Gaarco) - " + tr("Italian"))
translators.create_item(translators_root).set_text(0, " StarFang208 - " + tr("Italian"))
translators.create_item(translators_root).set_text(0, " azagaya - " + tr("Spanish"))
translators.create_item(translators_root).set_text(0, " Lilly And (KatieAnd) - " + tr("Spanish"))
translators.create_item(translators_root).set_text(0, " Agnis Aldiņš (NeZvers) - " + tr("Latvian"))
translators.create_item(translators_root).set_text(0, " Teashrock - " + tr("Esperanto"))
func _on_AboutDialog_popup_hide() -> void:
groups.clear()
developers.clear()
func _on_Groups_item_selected() -> void:
for child in credits.get_children():
if child != groups:
child.visible = false
var selected : String = groups.get_selected().get_metadata(0)
if "Developers" in selected:
developer_container.visible = true
elif "Contributors" in selected:
contributors_container.visible = true
elif "Donors" in selected:
donors_container.visible = true
elif "Translators" in selected:
translators_container.visible = true
func _on_Website_pressed() -> void:
OS.shell_open("https://www.orama-interactive.com/pixelorama")
func _on_GitHub_pressed() -> void:
OS.shell_open("https://github.com/Orama-Interactive/Pixelorama")
func _on_Donate_pressed() -> void:
OS.shell_open("https://www.patreon.com/OramaInteractive")

View file

@ -0,0 +1,209 @@
[gd_scene load_steps=6 format=2]
[ext_resource path="res://src/UI/Dialogs/AboutDialog.gd" type="Script" id=1]
[ext_resource path="res://Assets/Graphics/icon_64x64.png" type="Texture" id=2]
[ext_resource path="res://Assets/Fonts/Roboto-Italic.tres" type="DynamicFont" id=3]
[ext_resource path="res://Assets/Graphics/orama_64x64.png" type="Texture" id=4]
[ext_resource path="res://Assets/Fonts/Roboto-Small.tres" type="DynamicFont" id=5]
[node name="AboutDialog" type="WindowDialog"]
margin_right = 512.0
margin_bottom = 288.0
rect_min_size = Vector2( 512, 288 )
window_title = "About Pixelorama"
resizable = true
script = ExtResource( 1 )
[node name="AboutUI" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 12.0
margin_top = 4.0
margin_right = -12.0
margin_bottom = -8.0
alignment = 1
[node name="IconsButtons" type="HBoxContainer" parent="AboutUI"]
margin_right = 488.0
margin_bottom = 64.0
[node name="PixeloramaLogo" type="TextureRect" parent="AboutUI/IconsButtons"]
margin_right = 64.0
margin_bottom = 64.0
texture = ExtResource( 2 )
[node name="SloganAndLinks" type="CenterContainer" parent="AboutUI/IconsButtons"]
margin_left = 68.0
margin_right = 420.0
margin_bottom = 64.0
size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="AboutUI/IconsButtons/SloganAndLinks"]
margin_left = 64.0
margin_top = 12.0
margin_right = 288.0
margin_bottom = 51.0
[node name="Pixelorama" type="Label" parent="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer"]
margin_right = 224.0
margin_bottom = 15.0
custom_fonts/font = ExtResource( 3 )
text = "Pixelorama - Pixelate your dreams!"
align = 1
[node name="LinkButtons" type="HBoxContainer" parent="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer"]
margin_top = 19.0
margin_right = 224.0
margin_bottom = 39.0
[node name="Website" type="Button" parent="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer/LinkButtons"]
margin_right = 65.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "Website"
[node name="GitHub" type="Button" parent="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer/LinkButtons"]
margin_left = 69.0
margin_right = 162.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "GitHub Repo"
[node name="Donate" type="Button" parent="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer/LinkButtons"]
margin_left = 166.0
margin_right = 224.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
text = "Donate"
[node name="OramaLogo" type="TextureRect" parent="AboutUI/IconsButtons"]
margin_left = 424.0
margin_right = 488.0
margin_bottom = 64.0
texture = ExtResource( 4 )
[node name="HSeparator" type="HSeparator" parent="AboutUI"]
margin_top = 68.0
margin_right = 488.0
margin_bottom = 72.0
[node name="Credits" type="HSplitContainer" parent="AboutUI"]
margin_top = 76.0
margin_right = 488.0
margin_bottom = 233.0
size_flags_vertical = 3
[node name="Groups" type="Tree" parent="AboutUI/Credits"]
margin_right = 120.0
margin_bottom = 157.0
rect_min_size = Vector2( 120, 120 )
custom_constants/item_margin = -2
hide_root = true
[node name="Developers" type="VBoxContainer" parent="AboutUI/Credits"]
margin_left = 132.0
margin_right = 488.0
margin_bottom = 157.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="AboutUI/Credits/Developers"]
margin_right = 356.0
margin_bottom = 14.0
text = "Development Team"
[node name="DeveloperTree" type="Tree" parent="AboutUI/Credits/Developers"]
margin_top = 18.0
margin_right = 356.0
margin_bottom = 157.0
size_flags_vertical = 3
custom_constants/item_margin = -2
custom_constants/button_margin = 2
hide_root = true
[node name="Contributors" type="VBoxContainer" parent="AboutUI/Credits"]
visible = false
margin_left = 254.0
margin_right = 496.0
margin_bottom = 126.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="AboutUI/Credits/Contributors"]
margin_right = 242.0
margin_bottom = 14.0
text = "GitHub Contributors"
[node name="ContributorTree" type="Tree" parent="AboutUI/Credits/Contributors"]
margin_top = 18.0
margin_right = 242.0
margin_bottom = 126.0
size_flags_vertical = 3
custom_constants/item_margin = -2
hide_root = true
[node name="Donors" type="VBoxContainer" parent="AboutUI/Credits"]
visible = false
margin_left = 254.0
margin_right = 496.0
margin_bottom = 126.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="AboutUI/Credits/Donors"]
margin_right = 242.0
margin_bottom = 14.0
text = "Donors"
[node name="DonorTree" type="Tree" parent="AboutUI/Credits/Donors"]
margin_top = 18.0
margin_right = 242.0
margin_bottom = 126.0
size_flags_vertical = 3
custom_constants/item_margin = -2
hide_root = true
[node name="Translators" type="VBoxContainer" parent="AboutUI/Credits"]
visible = false
margin_left = 254.0
margin_right = 496.0
margin_bottom = 126.0
size_flags_horizontal = 3
[node name="Label" type="Label" parent="AboutUI/Credits/Translators"]
margin_right = 242.0
margin_bottom = 14.0
text = "Translators"
[node name="TranslatorTree" type="Tree" parent="AboutUI/Credits/Translators"]
margin_top = 18.0
margin_right = 242.0
margin_bottom = 126.0
size_flags_vertical = 3
custom_constants/item_margin = -2
hide_root = true
[node name="HSeparator2" type="HSeparator" parent="AboutUI"]
margin_top = 237.0
margin_right = 488.0
margin_bottom = 241.0
[node name="MadeBy" type="Label" parent="AboutUI"]
margin_top = 245.0
margin_right = 488.0
margin_bottom = 259.0
text = "Developed by Orama Interactive"
align = 1
[node name="Copyright" type="Label" parent="AboutUI"]
margin_top = 263.0
margin_right = 488.0
margin_bottom = 276.0
custom_fonts/font = ExtResource( 5 )
text = "Copyright 2019-2020 Orama Interactive"
align = 1
[connection signal="about_to_show" from="." to="." method="_on_AboutDialog_about_to_show"]
[connection signal="popup_hide" from="." to="." method="_on_AboutDialog_popup_hide"]
[connection signal="pressed" from="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer/LinkButtons/Website" to="." method="_on_Website_pressed"]
[connection signal="pressed" from="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer/LinkButtons/GitHub" to="." method="_on_GitHub_pressed"]
[connection signal="pressed" from="AboutUI/IconsButtons/SloganAndLinks/VBoxContainer/LinkButtons/Donate" to="." method="_on_Donate_pressed"]
[connection signal="item_selected" from="AboutUI/Credits/Groups" to="." method="_on_Groups_item_selected"]

View file

@ -0,0 +1,133 @@
extends ConfirmationDialog
onready var templates_options = $VBoxContainer/OptionsContainer/TemplatesOptions
onready var ratio_box = $VBoxContainer/OptionsContainer/RatioCheckBox
onready var width_value = $VBoxContainer/OptionsContainer/WidthValue
onready var height_value = $VBoxContainer/OptionsContainer/HeightValue
onready var fill_color_node = $VBoxContainer/OptionsContainer/FillColor
onready var size_value = Vector2()
# Template Id identifier
enum Templates {
TDefault = 0,
T16 = 1,
T32 = 2,
T64 = 3,
T128 = 4,
GB = 5,
GBA = 6,
NES_NTSC = 7,
NES_PAL = 8,
SNES_NTSC = 9,
SNES_PAL = 10
}
# Template actual value, without Default because we get it from Global
var TResolutions = {
Templates.T16: Vector2(16,16),
Templates.T32: Vector2(32,32),
Templates.T64: Vector2(64,64),
Templates.T128: Vector2(128,128),
Templates.GB: Vector2(160,144),
Templates.GBA: Vector2(240,160),
Templates.NES_NTSC: Vector2(256,224),
Templates.NES_PAL: Vector2(256,240),
Templates.SNES_NTSC: Vector2(512,448),
Templates.SNES_PAL: Vector2(512,480),
}
var TStrings ={
Templates.T16: "",
Templates.T32: "",
Templates.T64: "",
Templates.T128: "",
Templates.GB: "GB",
Templates.GBA: "GBA",
Templates.NES_NTSC: "NES (NTSC)",
Templates.NES_PAL: "NES (PAL)",
Templates.SNES_NTSC: "SNES (NTSC)",
Templates.SNES_PAL: "SNES (PAL)"
}
func _ready() -> void:
ratio_box.connect("pressed", self, "_on_RatioCheckBox_toggled", [ratio_box.pressed])
templates_options.connect("item_selected", self, "_on_TemplatesOptions_item_selected")
_CreateOptionList()
func _CreateOptionList() -> void:
for i in Templates.values():
if i > 0:
if TStrings[i] != "":
templates_options.add_item("{width}x{height} - {name}".format({"width":TResolutions[i].x, "height":TResolutions[i].y, "name":TStrings[i]}), i)
else:
templates_options.add_item("{width}x{height}".format({"width":TResolutions[i].x, "height":TResolutions[i].y}), i)
func _on_CreateNewImage_confirmed() -> void:
var width : int = width_value.value
var height : int = height_value.value
var fill_color : Color = fill_color_node.color
Global.clear_canvases()
Global.layers.clear()
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3),
# will new frames be linked boolean (4), Array of linked frames (5)]
Global.layers.append([tr("Layer") + " 0", true, false, HBoxContainer.new(), false, []])
Global.canvas = load("res://src/Canvas.tscn").instance()
Global.canvas.size = Vector2(width, height).floor()
Global.canvases.append(Global.canvas)
Global.canvas_parent.add_child(Global.canvas)
Global.current_layer = 0
Global.canvases = Global.canvases # To trigger Global.canvases_changed()
Global.current_frame = 0
Global.layers = Global.layers # To trigger Global.layers_changed()
Global.project_has_changed = false
if fill_color.a > 0:
Global.canvas.layers[0][0].fill(fill_color)
Global.canvas.layers[0][0].lock()
Global.canvas.update_texture(0)
func _on_CreateNewImage_about_to_show() -> void:
width_value.value = Global.default_image_width
height_value.value = Global.default_image_height
fill_color_node.color = Global.default_fill_color
templates_options.selected = Templates.TDefault
ratio_box.pressed = false
for spin_box in [width_value, height_value]:
if spin_box.is_connected("value_changed", self, "_on_SizeValue_value_changed"):
spin_box.disconnect("value_changed", self, "_on_SizeValue_value_changed")
var aspect_ratio: float
func _on_RatioCheckBox_toggled(_button_pressed: bool) -> void:
aspect_ratio = width_value.value / height_value.value
for spin_box in [width_value, height_value]:
if spin_box.is_connected("value_changed", self, "_on_SizeValue_value_changed"):
spin_box.disconnect("value_changed", self, "_on_SizeValue_value_changed")
else:
spin_box.connect("value_changed", self, "_on_SizeValue_value_changed")
func _on_SizeValue_value_changed(value: float) -> void:
if width_value.value == value:
height_value.value = width_value.value / aspect_ratio
if height_value.value == value:
width_value.value = height_value.value * aspect_ratio
func _on_TemplatesOptions_item_selected(id: int) -> void:
if id != Templates.TDefault:
size_value = TResolutions[id]
else:
width_value.value = Global.default_image_width
height_value.value = Global.default_image_height
width_value.value = size_value.x
height_value.value = size_value.y

View file

@ -0,0 +1,124 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Dialogs/CreateNewImage.gd" type="Script" id=1]
[node name="CreateNewImage" type="ConfirmationDialog"]
margin_right = 300.0
margin_bottom = 200.0
rect_min_size = Vector2( 375, 200 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 8.0
margin_top = 8.0
margin_right = 367.0
margin_bottom = 164.0
size_flags_horizontal = 0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ImageSize" type="Label" parent="VBoxContainer"]
margin_right = 359.0
margin_bottom = 14.0
text = "Image Size"
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
margin_top = 18.0
margin_right = 359.0
margin_bottom = 22.0
[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"]
margin_top = 26.0
margin_right = 359.0
margin_bottom = 154.0
custom_constants/vseparation = 4
custom_constants/hseparation = 2
columns = 2
[node name="TemplatesLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 3.0
margin_right = 112.0
margin_bottom = 17.0
text = "Templates:"
[node name="TemplatesOptions" type="OptionButton" parent="VBoxContainer/OptionsContainer"]
margin_left = 114.0
margin_right = 189.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
toggle_mode = false
text = "Default"
items = [ "Default", null, false, 0, null ]
selected = 0
[node name="RatioLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 29.0
margin_right = 112.0
margin_bottom = 43.0
text = "Lock aspect ratio:"
[node name="RatioCheckBox" type="CheckBox" parent="VBoxContainer/OptionsContainer"]
margin_left = 114.0
margin_top = 24.0
margin_right = 189.0
margin_bottom = 48.0
mouse_default_cursor_shape = 2
__meta__ = {
"_edit_use_anchors_": false
}
[node name="WidthLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 57.0
margin_right = 112.0
margin_bottom = 71.0
text = "Width:"
[node name="WidthValue" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
margin_left = 114.0
margin_top = 52.0
margin_right = 189.0
margin_bottom = 76.0
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="Height" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 85.0
margin_right = 112.0
margin_bottom = 99.0
text = "Height:"
[node name="HeightValue" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
margin_left = 114.0
margin_top = 80.0
margin_right = 189.0
margin_bottom = 104.0
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="FillColorLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 111.0
margin_right = 112.0
margin_bottom = 125.0
text = "Fill with color:"
[node name="FillColor" type="ColorPickerButton" parent="VBoxContainer/OptionsContainer"]
margin_left = 114.0
margin_top = 108.0
margin_right = 189.0
margin_bottom = 128.0
rect_min_size = Vector2( 64, 20 )
color = Color( 0, 0, 0, 0 )
[connection signal="about_to_show" from="." to="." method="_on_CreateNewImage_about_to_show"]
[connection signal="confirmed" from="." to="." method="_on_CreateNewImage_confirmed"]

View file

@ -0,0 +1,629 @@
extends AcceptDialog
enum ExportTab { FRAME = 0, SPRITESHEET = 1, ANIMATION = 2 }
var current_tab : int = ExportTab.FRAME
# All canvases and their layers processed/blended into images
var processed_images = [] # Image[]
# Frame options
var frame_number := 0
# Spritesheet options
enum Orientation { ROWS = 0, COLUMNS = 1 }
var orientation : int = Orientation.ROWS
# How many rows/columns before new line is added
var lines_count := 1
# Animation options
enum AnimationType { MULTIPLE_FILES = 0, ANIMATED = 1 }
var animation_type : int = AnimationType.MULTIPLE_FILES
var background_color : Color = Color.white
enum AnimationDirection { FORWARD = 0, BACKWARDS = 1, PING_PONG = 2 }
var direction : int = AnimationDirection.FORWARD
# Options
var resize := 100
var interpolation := 0 # Image.Interpolation
var new_dir_for_each_frame_tag : bool = true # you don't need to store this after export
# Export directory path and export file name
var directory_path := ""
var file_name := ""
var file_format : int = FileFormat.PNG
enum FileFormat { PNG = 0, GIF = 1}
var file_exists_alert = "File %s already exists. Overwrite?"
# Store all settings after export, enables a quick re-export with same settings
var was_exported : bool = false
var exported_tab : int
var exported_frame_number : int
var exported_orientation : int
var exported_lines_count : int
var exported_animation_type : int
var exported_background_color : Color
var exported_direction : int
var exported_resize : int
var exported_interpolation : int
var exported_directory_path : String
var exported_file_name : String
var exported_file_format : int
# Export coroutine signal
signal resume_export_function()
var stop_export = false
var animated_preview_current_frame := 0
var animated_preview_frames = []
func _ready() -> void:
$VBoxContainer/Tabs.add_tab("Frame")
$VBoxContainer/Tabs.add_tab("Spritesheet")
$VBoxContainer/Tabs.add_tab("Animation")
if OS.get_name() == "Windows":
add_button("Cancel", true, "cancel")
$Popups/FileExistsAlert.add_button("Cancel Export", true, "cancel")
else:
add_button("Cancel", false, "cancel")
$Popups/FileExistsAlert.add_button("Cancel Export", false, "cancel")
# Disable GIF export for unsupported platforms
if not $GifExporter.is_platform_supported():
$VBoxContainer/AnimationOptions/AnimationType.selected = AnimationType.MULTIPLE_FILES
$VBoxContainer/AnimationOptions/AnimationType.disabled = true
func show_tab() -> void:
$VBoxContainer/FrameOptions.hide()
$VBoxContainer/SpritesheetOptions.hide()
$VBoxContainer/AnimationOptions.hide()
match current_tab:
ExportTab.FRAME:
file_format = FileFormat.PNG
$VBoxContainer/File/FileFormat.selected = FileFormat.PNG
$FrameTimer.stop()
if not was_exported:
frame_number = Global.current_frame + 1
$VBoxContainer/FrameOptions/FrameNumber/FrameNumber.max_value = Global.canvases.size() + 1
$VBoxContainer/FrameOptions/FrameNumber/FrameNumber.value = frame_number
process_frame()
$VBoxContainer/FrameOptions.show()
ExportTab.SPRITESHEET:
file_format = FileFormat.PNG
$VBoxContainer/File/FileFormat.selected = FileFormat.PNG
$FrameTimer.stop()
if not was_exported:
orientation = Orientation.ROWS
lines_count = int(ceil(sqrt(Global.canvases.size())))
$VBoxContainer/SpritesheetOptions/Orientation/Orientation.selected = orientation
$VBoxContainer/SpritesheetOptions/Orientation/LinesCount.max_value = Global.canvases.size()
$VBoxContainer/SpritesheetOptions/Orientation/LinesCount.value = lines_count
$VBoxContainer/SpritesheetOptions/Orientation/LinesCountLabel.text = "Columns:"
process_spritesheet()
$VBoxContainer/SpritesheetOptions.show()
ExportTab.ANIMATION:
set_file_format_selector()
process_animation()
$VBoxContainer/AnimationOptions/AnimationType.selected = animation_type
$VBoxContainer/AnimationOptions/AnimatedOptions/BackgroundColor.color = background_color
$VBoxContainer/AnimationOptions/AnimatedOptions/Direction.selected = direction
$VBoxContainer/AnimationOptions.show()
set_preview()
$VBoxContainer/Tabs.current_tab = current_tab
func external_export() -> void:
restore_previous_export_settings()
match current_tab:
ExportTab.FRAME:
process_frame()
ExportTab.SPRITESHEET:
process_spritesheet()
ExportTab.ANIMATION:
process_animation()
export_processed_images(true)
func process_frame() -> void:
var canvas = Global.canvases[frame_number - 1]
var image := Image.new()
image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
blend_layers(image, canvas)
processed_images.clear()
processed_images.append(image)
func process_spritesheet() -> void:
# If rows mode selected calculate columns count and vice versa
var spritesheet_columns = lines_count if orientation == Orientation.ROWS else frames_divided_by_spritesheet_lines()
var spritesheet_rows = lines_count if orientation == Orientation.COLUMNS else frames_divided_by_spritesheet_lines()
var width = Global.canvas.size.x * spritesheet_columns
var height = Global.canvas.size.y * spritesheet_rows
var whole_image := Image.new()
whole_image.create(width, height, false, Image.FORMAT_RGBA8)
whole_image.lock()
var origin := Vector2.ZERO
var hh := 0
var vv := 0
for canvas in Global.canvases:
if orientation == Orientation.ROWS:
if vv < spritesheet_columns:
origin.x = canvas.size.x * vv
vv += 1
else:
hh += 1
origin.x = 0
vv = 1
origin.y = canvas.size.y * hh
else:
if hh < spritesheet_rows:
origin.y = canvas.size.y * hh
hh += 1
else:
vv += 1
origin.y = 0
hh = 1
origin.x = canvas.size.x * vv
blend_layers(whole_image, canvas, origin)
processed_images.clear()
processed_images.append(whole_image)
func process_animation() -> void:
processed_images.clear()
for canvas in Global.canvases:
var image := Image.new()
image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
blend_layers(image, canvas)
processed_images.append(image)
func set_preview() -> void:
remove_previews()
if processed_images.size() == 1 and current_tab != ExportTab.ANIMATION:
$VBoxContainer/PreviewScroll/Previews.columns = 1
add_image_preview(processed_images[0])
else:
match animation_type:
AnimationType.MULTIPLE_FILES:
$VBoxContainer/PreviewScroll/Previews.columns = ceil(sqrt(processed_images.size()))
for i in range(processed_images.size()):
add_image_preview(processed_images[i], i + 1)
AnimationType.ANIMATED:
$VBoxContainer/PreviewScroll/Previews.columns = 1
add_animated_preview()
func add_image_preview(image: Image, canvas_number: int = -1) -> void:
var container = create_preview_container()
var preview = create_preview_rect()
preview.texture = ImageTexture.new()
preview.texture.create_from_image(image, 0)
container.add_child(preview)
if canvas_number != -1:
var label = Label.new()
label.align = Label.ALIGN_CENTER
label.text = String(canvas_number)
container.add_child(label)
$VBoxContainer/PreviewScroll/Previews.add_child(container)
func add_animated_preview() -> void:
animated_preview_current_frame = processed_images.size() - 1 if direction == AnimationDirection.BACKWARDS else 0
animated_preview_frames = []
for processed_image in processed_images:
var texture = ImageTexture.new()
texture.create_from_image(processed_image, 0)
animated_preview_frames.push_back(texture)
var container = create_preview_container()
container.name = "PreviewContainer"
var preview = create_preview_rect()
preview.name = "Preview"
preview.texture = animated_preview_frames[animated_preview_current_frame]
container.add_child(preview)
$VBoxContainer/PreviewScroll/Previews.add_child(container)
$FrameTimer.start()
func create_preview_container() -> VBoxContainer:
var container = VBoxContainer.new()
container.size_flags_horizontal = SIZE_EXPAND_FILL
container.size_flags_vertical = SIZE_EXPAND_FILL
container.rect_min_size = Vector2(0, 128)
return container
func create_preview_rect() -> TextureRect:
var preview = TextureRect.new()
preview.expand = true
preview.size_flags_horizontal = SIZE_EXPAND_FILL
preview.size_flags_vertical = SIZE_EXPAND_FILL
preview.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
return preview
func remove_previews() -> void:
for child in $VBoxContainer/PreviewScroll/Previews.get_children():
child.free()
func get_proccessed_image_animation_tag_and_start_id(processed_image_id : int) -> Array:
var result_animation_tag_and_start_id = null
for animation_tag in Global.animation_tags:
# Check if processed image is in frame tag and assign frame tag and start id if yes
# Then stop
if (processed_image_id + 1) >= animation_tag[2] and (processed_image_id + 1) <= animation_tag[3]:
result_animation_tag_and_start_id = [animation_tag[0], animation_tag[2]]
break
return result_animation_tag_and_start_id
func export_processed_images(ignore_overwrites : bool) -> void:
# Stop export if directory path or file name are not valid
var dir = Directory.new()
if not dir.dir_exists(directory_path) or not file_name.is_valid_filename():
$Popups/PathValidationAlert.popup_centered()
return
# Check export paths
var export_paths = []
for i in range(processed_images.size()):
stop_export = false
var multiple_files := true if (current_tab == ExportTab.ANIMATION && animation_type == AnimationType.MULTIPLE_FILES) else false
var export_path = create_export_path(multiple_files, i + 1)
# If user want to create new directory for each animation tag then check if directories exist and create them if not
if multiple_files and new_dir_for_each_frame_tag:
var frame_tag_directory := Directory.new()
if not frame_tag_directory.dir_exists(export_path.get_base_dir()):
frame_tag_directory.open(directory_path)
frame_tag_directory.make_dir(export_path.get_base_dir().get_file())
# Check if the file already exists
var fileCheck = File.new()
if fileCheck.file_exists(export_path):
# Ask user if he want's to overwrite the file
if not was_exported or (was_exported and not ignore_overwrites):
# Overwrite existing file?
$Popups/FileExistsAlert.dialog_text = file_exists_alert % export_path
$Popups/FileExistsAlert.popup_centered()
# Stops the function until the user decides if he want's to overwrite
yield(self, "resume_export_function")
if stop_export:
# User decided to stop export
return
export_paths.append(export_path)
# Only get one export path if single file animated image is exported
if current_tab == ExportTab.ANIMATION && animation_type == AnimationType.ANIMATED:
break
# Scale images that are to export
scale_processed_images()
if current_tab == ExportTab.ANIMATION && animation_type == AnimationType.ANIMATED:
var frame_delay_in_ms = Global.animation_timer.wait_time * 100
$GifExporter.begin_export(export_paths[0], processed_images[0].get_width(), processed_images[0].get_height(), frame_delay_in_ms, 0)
match direction:
AnimationDirection.FORWARD:
for i in range(processed_images.size()):
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
AnimationDirection.BACKWARDS:
for i in range(processed_images.size() - 1, -1, -1):
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
AnimationDirection.PING_PONG:
for i in range(0, processed_images.size()):
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
for i in range(processed_images.size() - 2, 0, -1):
$GifExporter.write_frame(processed_images[i], background_color, frame_delay_in_ms)
$GifExporter.end_export()
else:
for i in range(processed_images.size()):
var err = processed_images[i].save_png(export_paths[i])
if err != OK:
OS.alert("Can't save file")
# Store settings for quick export and when the dialog is opened again
was_exported = true
store_export_settings()
Global.file_menu.get_popup().set_item_text(6, tr("Export") + " %s" % (file_name + file_format_string(file_format)))
Global.notification_label("File(s) exported")
hide()
# Blends canvas layers into passed image starting from the origin position
func blend_layers(image: Image, canvas: Canvas, origin: Vector2 = Vector2(0, 0)) -> void:
image.lock()
var layer_i := 0
for layer in canvas.layers:
if Global.layers[layer_i][1]:
var layer_image := Image.new()
layer_image.copy_from(layer[0])
layer_image.lock()
if layer[2] < 1: # If we have layer transparency
for xx in layer_image.get_size().x:
for yy in layer_image.get_size().y:
var pixel_color := layer_image.get_pixel(xx, yy)
var alpha : float = pixel_color.a * layer[2]
layer_image.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
canvas.blend_rect(image, layer_image, Rect2(canvas.position, canvas.size), origin)
layer_i += 1
image.unlock()
func scale_processed_images() -> void:
for processed_image in processed_images:
if resize != 100:
processed_image.unlock()
processed_image.resize(processed_image.get_size().x * resize / 100, processed_image.get_size().y * resize / 100, interpolation)
func create_export_path(multifile: bool, frame: int = 0) -> String:
var path = file_name
# Only append frame number when there are multiple files exported
if multifile:
var frame_tag_and_start_id = get_proccessed_image_animation_tag_and_start_id(frame - 1)
# Check if exported frame is in frame tag
if frame_tag_and_start_id != null:
var frame_tag = frame_tag_and_start_id[0]
var start_id = frame_tag_and_start_id[1]
# Remove unallowed characters in frame tag directory
var regex := RegEx.new()
regex.compile("[^a-zA-Z0-9_]+")
var frame_tag_dir = regex.sub(frame_tag, "", true)
if new_dir_for_each_frame_tag:
# Add frame tag if frame has one
# (frame - start_id + 1) Makes frames id to start from 1 in each frame tag directory
path += "_" + frame_tag_dir + "_" + String(frame - start_id + 1)
return directory_path.plus_file(frame_tag_dir).plus_file(path + file_format_string(file_format))
else:
# Add frame tag if frame has one
# (frame - start_id + 1) Makes frames id to start from 1 in each frame tag
path += "_" + frame_tag_dir + "_" + String(frame - start_id + 1)
else:
path += "_" + String(frame)
return directory_path.plus_file(path + file_format_string(file_format))
func frames_divided_by_spritesheet_lines() -> int:
return int(ceil(Global.canvases.size() / float(lines_count)))
func file_format_string(format_enum : int) -> String:
match format_enum:
0: # PNG
return '.png'
1: # GIF
return '.gif'
_:
return ''
func set_file_format_selector() -> void:
$VBoxContainer/AnimationOptions/MultipleAnimationsDirectories.visible = false
match animation_type:
AnimationType.MULTIPLE_FILES:
file_format = FileFormat.PNG
$VBoxContainer/File/FileFormat.selected = FileFormat.PNG
$FrameTimer.stop()
$VBoxContainer/AnimationOptions/AnimatedOptions.hide()
$VBoxContainer/AnimationOptions/MultipleAnimationsDirectories.pressed = new_dir_for_each_frame_tag
$VBoxContainer/AnimationOptions/MultipleAnimationsDirectories.visible = true
AnimationType.ANIMATED:
file_format = FileFormat.GIF
$VBoxContainer/File/FileFormat.selected = FileFormat.GIF
$FrameTimer.wait_time = Global.animation_timer.wait_time
$VBoxContainer/AnimationOptions/AnimatedOptions.show()
func store_export_settings() -> void:
exported_tab = current_tab
exported_frame_number = frame_number
exported_orientation = orientation
exported_lines_count = lines_count
exported_animation_type = animation_type
exported_background_color = background_color
exported_direction = direction
exported_resize = resize
exported_interpolation = interpolation
exported_directory_path = directory_path
exported_file_name = file_name
exported_file_format = file_format
# Fill the dialog with previous export settings
func restore_previous_export_settings() -> void:
current_tab = exported_tab
frame_number = exported_frame_number if exported_frame_number <= Global.canvases.size() else Global.canvases.size()
orientation = exported_orientation
lines_count = exported_lines_count
animation_type = exported_animation_type
background_color = exported_background_color
direction = exported_direction
resize = exported_resize
interpolation = exported_interpolation
directory_path = exported_directory_path
file_name = exported_file_name
file_format = exported_file_format
func _on_ExportDialog_about_to_show() -> void:
# If export already occured - fill the dialog with previous export settings
if was_exported:
restore_previous_export_settings()
if directory_path.empty():
directory_path = OS.get_system_dir(OS.SYSTEM_DIR_DESKTOP)
# If export already occured - sets gui to show previous settings
$VBoxContainer/Options/Resize.value = resize
$VBoxContainer/Options/Interpolation.selected = interpolation
$VBoxContainer/Path/PathLineEdit.text = directory_path
$VBoxContainer/File/FileLineEdit.text = file_name
$VBoxContainer/File/FileFormat.selected = file_format
show_tab()
for child in $Popups.get_children(): # Set the theme for the popups
child.theme = Global.control.theme
file_exists_alert = tr("File %s already exists. Overwrite?") # Update translation
#$VBoxContainer/Tabs.set_tab_title(0, "Frame")
func _on_Tabs_tab_clicked(tab : int) -> void:
current_tab = tab
show_tab()
func _on_Frame_value_changed(value: float) -> void:
frame_number = value
process_frame()
set_preview()
func _on_Orientation_item_selected(id : int) -> void:
orientation = id
if orientation == Orientation.ROWS:
$VBoxContainer/SpritesheetOptions/Orientation/LinesCountLabel.text = "Columns:"
else:
$VBoxContainer/SpritesheetOptions/Orientation/LinesCountLabel.text = "Rows:"
$VBoxContainer/SpritesheetOptions/Orientation/LinesCount.value = frames_divided_by_spritesheet_lines()
process_spritesheet()
set_preview()
func _on_LinesCount_value_changed(value : float) -> void:
lines_count = value
process_spritesheet()
set_preview()
func _on_AnimationType_item_selected(id : int) -> void:
animation_type = id
set_file_format_selector()
set_preview()
func _on_BackgroundColor_color_changed(color : Color) -> void:
background_color = color
func _on_Direction_item_selected(id : int) -> void:
direction = id
match id:
AnimationDirection.FORWARD:
animated_preview_current_frame = 0
AnimationDirection.BACKWARDS:
animated_preview_current_frame = processed_images.size() - 1
AnimationDirection.PING_PONG:
animated_preview_current_frame = 0
pingpong_direction = AnimationDirection.FORWARD
func _on_Resize_value_changed(value : float) -> void:
resize = value
func _on_Interpolation_item_selected(id: int) -> void:
interpolation = id
func _on_ExportDialog_confirmed() -> void:
export_processed_images(false)
func _on_ExportDialog_custom_action(action : String) -> void:
if action == "cancel":
hide()
func _on_PathButton_pressed() -> void:
$Popups/PathDialog.popup_centered()
func _on_PathLineEdit_text_changed(new_text : String) -> void:
directory_path = new_text
func _on_FileLineEdit_text_changed(new_text : String) -> void:
file_name = new_text
func _on_FileDialog_dir_selected(dir : String) -> void:
$VBoxContainer/Path/PathLineEdit.text = dir
directory_path = dir
func _on_FileFormat_item_selected(id : int) -> void:
file_format = id
func _on_FileExistsAlert_confirmed() -> void:
# Overwrite existing file
$Popups/FileExistsAlert.dialog_text = file_exists_alert
stop_export = false
emit_signal("resume_export_function")
func _on_FileExistsAlert_custom_action(action : String) -> void:
if action == "cancel":
# Cancel export
$Popups/FileExistsAlert.dialog_text = file_exists_alert
stop_export = true
emit_signal("resume_export_function")
$Popups/FileExistsAlert.hide()
var pingpong_direction = AnimationDirection.FORWARD
func _on_FrameTimer_timeout() -> void:
$VBoxContainer/PreviewScroll/Previews/PreviewContainer/Preview.texture = animated_preview_frames[animated_preview_current_frame]
match direction:
AnimationDirection.FORWARD:
if animated_preview_current_frame == animated_preview_frames.size() - 1:
animated_preview_current_frame = 0
else:
animated_preview_current_frame += 1
AnimationDirection.BACKWARDS:
if animated_preview_current_frame == 0:
animated_preview_current_frame = processed_images.size() - 1
else:
animated_preview_current_frame -= 1
AnimationDirection.PING_PONG:
match pingpong_direction:
AnimationDirection.FORWARD:
if animated_preview_current_frame == animated_preview_frames.size() - 1:
pingpong_direction = AnimationDirection.BACKWARDS
animated_preview_current_frame -= 1
if animated_preview_current_frame <= 0:
animated_preview_current_frame = 0
else:
animated_preview_current_frame += 1
AnimationDirection.BACKWARDS:
if animated_preview_current_frame == 0:
animated_preview_current_frame += 1
if animated_preview_current_frame >= animated_preview_frames.size() - 1:
animated_preview_current_frame = 0
pingpong_direction = AnimationDirection.FORWARD
else:
animated_preview_current_frame -= 1
func _on_ExportDialog_popup_hide() -> void:
$FrameTimer.stop()
func _on_MultipleAnimationsDirectories_toggled(button_pressed : bool) -> void:
new_dir_for_each_frame_tag = button_pressed

View file

@ -0,0 +1,390 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://src/UI/Dialogs/ExportDialog.gd" type="Script" id=1]
[ext_resource path="res://addons/godot-gifexporter/src/GifExporter.gd" type="Script" id=2]
[node name="ExportDialog" type="AcceptDialog"]
margin_right = 532.0
margin_bottom = 530.0
rect_min_size = Vector2( 456, 530 )
window_title = "Export..."
resizable = true
dialog_hide_on_ok = false
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 8.0
margin_top = 8.0
margin_right = 524.0
margin_bottom = 494.0
rect_min_size = Vector2( 330, 0 )
size_flags_vertical = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Tabs" type="Tabs" parent="VBoxContainer"]
margin_right = 516.0
margin_bottom = 24.0
size_flags_vertical = 0
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
margin_top = 28.0
margin_right = 516.0
margin_bottom = 32.0
[node name="PreviewLabel" type="Label" parent="VBoxContainer"]
margin_top = 36.0
margin_right = 516.0
margin_bottom = 50.0
text = "Preview:"
[node name="PreviewScroll" type="ScrollContainer" parent="VBoxContainer"]
margin_top = 54.0
margin_right = 516.0
margin_bottom = 274.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="Previews" type="GridContainer" parent="VBoxContainer/PreviewScroll"]
margin_right = 516.0
margin_bottom = 220.0
size_flags_horizontal = 3
size_flags_vertical = 3
columns = 3
[node name="FrameOptions" type="VBoxContainer" parent="VBoxContainer"]
margin_top = 278.0
margin_right = 516.0
margin_bottom = 302.0
[node name="FrameNumber" type="HBoxContainer" parent="VBoxContainer/FrameOptions"]
margin_right = 516.0
margin_bottom = 24.0
[node name="FrameNumberLabel" type="Label" parent="VBoxContainer/FrameOptions/FrameNumber"]
margin_top = 5.0
margin_right = 44.0
margin_bottom = 19.0
text = "Frame:"
[node name="FrameNumber" type="SpinBox" parent="VBoxContainer/FrameOptions/FrameNumber"]
margin_left = 48.0
margin_right = 516.0
margin_bottom = 24.0
rect_min_size = Vector2( 100, 0 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 1.0
page = 1.0
value = 1.0
rounded = true
align = 2
[node name="SpritesheetOptions" type="VBoxContainer" parent="VBoxContainer"]
margin_top = 306.0
margin_right = 516.0
margin_bottom = 330.0
[node name="Orientation" type="HBoxContainer" parent="VBoxContainer/SpritesheetOptions"]
margin_right = 516.0
margin_bottom = 24.0
alignment = 1
[node name="OrientationLabel" type="Label" parent="VBoxContainer/SpritesheetOptions/Orientation"]
margin_top = 5.0
margin_right = 77.0
margin_bottom = 19.0
text = "Orientation:"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Orientation" type="OptionButton" parent="VBoxContainer/SpritesheetOptions/Orientation"]
margin_left = 81.0
margin_right = 264.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Rows"
items = [ "Rows", null, false, 0, null, "Columns", null, false, 1, null ]
selected = 0
[node name="LinesCountLabel" type="Label" parent="VBoxContainer/SpritesheetOptions/Orientation"]
margin_left = 268.0
margin_top = 5.0
margin_right = 328.0
margin_bottom = 19.0
text = "Columns:"
[node name="LinesCount" type="SpinBox" parent="VBoxContainer/SpritesheetOptions/Orientation"]
margin_left = 332.0
margin_right = 516.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 1.0
max_value = 1000.0
value = 1.0
align = 2
[node name="AnimationOptions" type="VBoxContainer" parent="VBoxContainer"]
margin_top = 334.0
margin_right = 516.0
margin_bottom = 386.0
[node name="AnimationType" type="OptionButton" parent="VBoxContainer/AnimationOptions"]
margin_right = 516.0
margin_bottom = 24.0
rect_min_size = Vector2( 0, 24 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "All frames as multiple files"
items = [ "All frames as multiple files", null, false, 0, null, "All frames as a single file animation", null, false, 1, null ]
selected = 0
[node name="MultipleAnimationsDirectories" type="CheckBox" parent="VBoxContainer/AnimationOptions"]
visible = false
margin_top = 28.0
margin_right = 516.0
margin_bottom = 52.0
hint_tooltip = "Creates multiple files but every file is stored in different directory that corresponds to its frame tag"
text = "Create new directory for each frame tag"
[node name="AnimatedOptions" type="HBoxContainer" parent="VBoxContainer/AnimationOptions"]
margin_top = 28.0
margin_right = 516.0
margin_bottom = 52.0
rect_min_size = Vector2( 0, 24 )
[node name="BackgroundColorLabel" type="Label" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
margin_top = 5.0
margin_right = 78.0
margin_bottom = 19.0
text = "Background:"
valign = 1
[node name="BackgroundColor" type="ColorPickerButton" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
margin_left = 82.0
margin_right = 263.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 7
color = Color( 1, 1, 1, 1 )
edit_alpha = false
[node name="DirectionLabel" type="Label" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
margin_left = 267.0
margin_top = 5.0
margin_right = 330.0
margin_bottom = 19.0
text = "Direction:"
[node name="Direction" type="OptionButton" parent="VBoxContainer/AnimationOptions/AnimatedOptions"]
margin_left = 334.0
margin_right = 516.0
margin_bottom = 24.0
rect_min_size = Vector2( 100, 0 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Forward"
items = [ "Forward", null, false, 0, null, "Backwards", null, false, 1, null, "Ping-Pong", null, false, 2, null ]
selected = 0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"]
margin_top = 390.0
margin_right = 516.0
margin_bottom = 394.0
[node name="Options" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 398.0
margin_right = 516.0
margin_bottom = 422.0
[node name="ResizeLabel" type="Label" parent="VBoxContainer/Options"]
margin_top = 5.0
margin_right = 46.0
margin_bottom = 19.0
rect_min_size = Vector2( 30, 0 )
text = "Resize:"
align = 2
[node name="Resize" type="SpinBox" parent="VBoxContainer/Options"]
margin_left = 50.0
margin_right = 235.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 10.0
max_value = 1000.0
step = 100.0
value = 100.0
align = 2
suffix = "%"
[node name="InterpolationLabel" type="Label" parent="VBoxContainer/Options"]
margin_left = 239.0
margin_top = 5.0
margin_right = 326.0
margin_bottom = 19.0
rect_min_size = Vector2( 30, 0 )
text = "Interpolation:"
align = 2
[node name="Interpolation" type="OptionButton" parent="VBoxContainer/Options"]
margin_left = 330.0
margin_right = 516.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Nearest"
align = 2
items = [ "Nearest", null, false, 0, null, "Bilinear", null, false, 1, null, "Cubic", null, false, 2, null, "Trilinear", null, false, 3, null, "Lanczos", null, false, 4, null ]
selected = 0
[node name="HSeparator3" type="HSeparator" parent="VBoxContainer"]
margin_top = 426.0
margin_right = 516.0
margin_bottom = 430.0
[node name="Path" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 434.0
margin_right = 516.0
margin_bottom = 458.0
[node name="Label" type="Label" parent="VBoxContainer/Path"]
margin_top = 5.0
margin_right = 32.0
margin_bottom = 19.0
rect_min_size = Vector2( 30, 0 )
text = "Path:"
[node name="PathLineEdit" type="LineEdit" parent="VBoxContainer/Path"]
margin_left = 36.0
margin_right = 453.0
margin_bottom = 24.0
size_flags_horizontal = 3
align = 2
[node name="PathButton" type="Button" parent="VBoxContainer/Path"]
margin_left = 457.0
margin_right = 516.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
text = "Browse"
[node name="File" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 462.0
margin_right = 516.0
margin_bottom = 486.0
[node name="Label" type="Label" parent="VBoxContainer/File"]
margin_top = 5.0
margin_right = 30.0
margin_bottom = 19.0
rect_min_size = Vector2( 30, 0 )
text = "File:"
[node name="FileLineEdit" type="LineEdit" parent="VBoxContainer/File"]
margin_left = 34.0
margin_right = 376.0
margin_bottom = 24.0
size_flags_horizontal = 3
align = 2
[node name="FileFormat" type="OptionButton" parent="VBoxContainer/File"]
margin_left = 380.0
margin_right = 516.0
margin_bottom = 24.0
rect_min_size = Vector2( 130, 0 )
mouse_default_cursor_shape = 8
disabled = true
text = ".png; PNG Image"
items = [ ".png; PNG Image", null, false, 0, null, ".gif; GIF Image", null, false, 1, null ]
selected = 0
[node name="Popups" type="Node" parent="."]
[node name="PathDialog" type="FileDialog" parent="Popups"]
margin_left = 8.0
margin_top = 8.0
margin_right = 448.0
margin_bottom = 494.0
rect_min_size = Vector2( 440, 300 )
size_flags_horizontal = 0
size_flags_vertical = 0
window_title = "Otwórz katalog"
resizable = true
mode = 2
access = 2
current_dir = "E:/Projekty/Godot/Pixelorama"
current_path = "E:/Projekty/Godot/Pixelorama/"
[node name="PathValidationAlert" type="AcceptDialog" parent="Popups"]
margin_left = 8.0
margin_top = 180.0
margin_right = 448.0
margin_bottom = 280.0
size_flags_horizontal = 0
size_flags_vertical = 0
window_title = "Alarm!"
resizable = true
dialog_text = "Directory path or file name is not valid!"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="FileExistsAlert" type="AcceptDialog" parent="Popups"]
margin_left = 8.0
margin_top = 180.0
margin_right = 448.0
margin_bottom = 280.0
size_flags_horizontal = 0
size_flags_vertical = 0
window_title = "Alarm!"
resizable = true
dialog_text = "File %s already exists. Overwrite?"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="FrameTimer" type="Timer" parent="."]
__meta__ = {
"_editor_description_": "Timer to advance animation frames in animation preview."
}
[node name="GifExporter" type="Node" parent="."]
script = ExtResource( 2 )
__meta__ = {
"_editor_description_": ""
}
[connection signal="about_to_show" from="." to="." method="_on_ExportDialog_about_to_show"]
[connection signal="confirmed" from="." to="." method="_on_ExportDialog_confirmed"]
[connection signal="custom_action" from="." to="." method="_on_ExportDialog_custom_action"]
[connection signal="popup_hide" from="." to="." method="_on_ExportDialog_popup_hide"]
[connection signal="tab_clicked" from="VBoxContainer/Tabs" to="." method="_on_Tabs_tab_clicked"]
[connection signal="value_changed" from="VBoxContainer/FrameOptions/FrameNumber/FrameNumber" to="." method="_on_Frame_value_changed"]
[connection signal="item_selected" from="VBoxContainer/SpritesheetOptions/Orientation/Orientation" to="." method="_on_Orientation_item_selected"]
[connection signal="value_changed" from="VBoxContainer/SpritesheetOptions/Orientation/LinesCount" to="." method="_on_LinesCount_value_changed"]
[connection signal="item_selected" from="VBoxContainer/AnimationOptions/AnimationType" to="." method="_on_AnimationType_item_selected"]
[connection signal="toggled" from="VBoxContainer/AnimationOptions/MultipleAnimationsDirectories" to="." method="_on_MultipleAnimationsDirectories_toggled"]
[connection signal="color_changed" from="VBoxContainer/AnimationOptions/AnimatedOptions/BackgroundColor" to="." method="_on_BackgroundColor_color_changed"]
[connection signal="item_selected" from="VBoxContainer/AnimationOptions/AnimatedOptions/Direction" to="." method="_on_Direction_item_selected"]
[connection signal="value_changed" from="VBoxContainer/Options/Resize" to="." method="_on_Resize_value_changed"]
[connection signal="item_selected" from="VBoxContainer/Options/Interpolation" to="." method="_on_Interpolation_item_selected"]
[connection signal="text_changed" from="VBoxContainer/Path/PathLineEdit" to="." method="_on_PathLineEdit_text_changed"]
[connection signal="pressed" from="VBoxContainer/Path/PathButton" to="." method="_on_PathButton_pressed"]
[connection signal="text_changed" from="VBoxContainer/File/FileLineEdit" to="." method="_on_FileLineEdit_text_changed"]
[connection signal="item_selected" from="VBoxContainer/File/FileFormat" to="." method="_on_FileFormat_item_selected"]
[connection signal="dir_selected" from="Popups/PathDialog" to="." method="_on_FileDialog_dir_selected"]
[connection signal="confirmed" from="Popups/FileExistsAlert" to="." method="_on_FileExistsAlert_confirmed"]
[connection signal="custom_action" from="Popups/FileExistsAlert" to="." method="_on_FileExistsAlert_custom_action"]
[connection signal="timeout" from="FrameTimer" to="." method="_on_FrameTimer_timeout"]

View file

@ -0,0 +1,134 @@
extends AcceptDialog
var current_tag_id := 0
var tag_vboxes := []
var delete_tag_button : Button
onready var main_vbox_cont : VBoxContainer = $VBoxContainer/ScrollContainer/VBoxTagContainer
onready var add_tag_button : TextureButton = $VBoxContainer/ScrollContainer/VBoxTagContainer/AddTag
onready var options_dialog = $TagOptions
func _on_FrameTagDialog_about_to_show() -> void:
Global.can_draw = false
for vbox in tag_vboxes:
vbox.queue_free()
tag_vboxes.clear()
var i := 0
for tag in Global.animation_tags:
var vbox_cont := VBoxContainer.new()
var hbox_cont := HBoxContainer.new()
var tag_label := Label.new()
if tag[2] == tag[3]:
tag_label.text = "Tag %s (Frame %s)" % [i + 1, tag[2]]
else:
tag_label.text = "Tag %s (Frames %s-%s)" % [i + 1, tag[2], tag[3]]
hbox_cont.add_child(tag_label)
var edit_button := Button.new()
edit_button.text = "Edit"
edit_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
edit_button.connect("pressed", self, "_on_EditButton_pressed", [i])
hbox_cont.add_child(edit_button)
vbox_cont.add_child(hbox_cont)
var name_label := Label.new()
name_label.text = tag[0]
name_label.modulate = tag[1]
vbox_cont.add_child(name_label)
var hsep := HSeparator.new()
hsep.size_flags_horizontal = SIZE_EXPAND_FILL
vbox_cont.add_child(hsep)
main_vbox_cont.add_child(vbox_cont)
tag_vboxes.append(vbox_cont)
i += 1
add_tag_button.visible = true
main_vbox_cont.move_child(add_tag_button, main_vbox_cont.get_child_count() - 1)
func _on_FrameTagDialog_popup_hide() -> void:
Global.can_draw = true
func _on_AddTag_pressed() -> void:
options_dialog.popup_centered()
current_tag_id = Global.animation_tags.size()
options_dialog.get_node("GridContainer/FromSpinBox").value = Global.current_frame + 1
options_dialog.get_node("GridContainer/ToSpinBox").value = Global.current_frame + 1
func _on_EditButton_pressed(_tag_id : int) -> void:
options_dialog.popup_centered()
current_tag_id = _tag_id
options_dialog.get_node("GridContainer/NameLineEdit").text = Global.animation_tags[_tag_id][0]
options_dialog.get_node("GridContainer/ColorPickerButton").color = Global.animation_tags[_tag_id][1]
options_dialog.get_node("GridContainer/FromSpinBox").value = Global.animation_tags[_tag_id][2]
options_dialog.get_node("GridContainer/ToSpinBox").value = Global.animation_tags[_tag_id][3]
if !delete_tag_button:
delete_tag_button = options_dialog.add_button("Delete Tag", true, "delete_tag")
else:
delete_tag_button.visible = true
func _on_TagOptions_confirmed() -> void:
var tag_name : String = options_dialog.get_node("GridContainer/NameLineEdit").text
var tag_color : Color = options_dialog.get_node("GridContainer/ColorPickerButton").color
var tag_from : int = options_dialog.get_node("GridContainer/FromSpinBox").value
var tag_to : int = options_dialog.get_node("GridContainer/ToSpinBox").value
if tag_to > Global.canvases.size():
tag_to = Global.canvases.size()
if tag_from > tag_to:
tag_from = tag_to
var new_animation_tags := Global.animation_tags.duplicate(true)
if current_tag_id == Global.animation_tags.size():
new_animation_tags.append([tag_name, tag_color, tag_from, tag_to])
else:
new_animation_tags[current_tag_id][0] = tag_name
new_animation_tags[current_tag_id][1] = tag_color
new_animation_tags[current_tag_id][2] = tag_from
new_animation_tags[current_tag_id][3] = tag_to
# Handle Undo/Redo
Global.undos += 1
Global.undo_redo.create_action("Modify Frame Tag")
Global.undo_redo.add_do_method(Global, "general_redo")
Global.undo_redo.add_undo_method(Global, "general_undo")
Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags)
Global.undo_redo.add_undo_property(Global, "animation_tags", Global.animation_tags)
Global.undo_redo.commit_action()
_on_FrameTagDialog_about_to_show()
func _on_TagOptions_custom_action(action : String) -> void:
if action == "delete_tag":
var new_animation_tags := Global.animation_tags.duplicate(true)
new_animation_tags.remove(current_tag_id)
# Handle Undo/Redo
Global.undos += 1
Global.undo_redo.create_action("Delete Frame Tag")
Global.undo_redo.add_do_method(Global, "general_redo")
Global.undo_redo.add_undo_method(Global, "general_undo")
Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags)
Global.undo_redo.add_undo_property(Global, "animation_tags", Global.animation_tags)
Global.undo_redo.commit_action()
options_dialog.hide()
_on_FrameTagDialog_about_to_show()
func _on_TagOptions_popup_hide() -> void:
if delete_tag_button:
delete_tag_button.visible = false
func _on_PlayOnlyTags_toggled(button_pressed : bool) -> void:
Global.play_only_tags = button_pressed

View file

@ -0,0 +1,170 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://src/UI/Dialogs/FrameTagDialog.gd" type="Script" id=1]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/new_frame.png" type="Texture" id=2]
[node name="FrameTagDialog" type="AcceptDialog"]
margin_right = 83.0
margin_bottom = 58.0
rect_min_size = Vector2( 400, 200 )
window_title = "Frame Tag Properties"
resizable = true
script = ExtResource( 1 )
[node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 8.0
margin_top = 8.0
margin_right = -8.0
margin_bottom = -36.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"]
margin_right = 384.0
margin_bottom = 128.0
size_flags_horizontal = 3
size_flags_vertical = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxTagContainer" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"]
margin_right = 384.0
margin_bottom = 28.0
size_flags_horizontal = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HSeparator" type="HSeparator" parent="VBoxContainer/ScrollContainer/VBoxTagContainer"]
margin_right = 384.0
margin_bottom = 4.0
size_flags_horizontal = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AddTag" type="Button" parent="VBoxContainer/ScrollContainer/VBoxTagContainer" groups=[
"UIButtons",
]]
margin_top = 8.0
margin_right = 20.0
margin_bottom = 28.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Add a new frame tag"
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="VBoxContainer/ScrollContainer/VBoxTagContainer/AddTag"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -6.0
margin_top = -6.0
margin_right = 6.0
margin_bottom = 6.0
texture = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PlayOnlyTags" type="CheckBox" parent="VBoxContainer"]
margin_top = 132.0
margin_right = 333.0
margin_bottom = 156.0
hint_tooltip = "If it's selected, the animation plays only on the frames that have the same tag.
If it's not, the animation will play for all frames, ignoring tags."
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
pressed = true
text = "Animation plays only on frames of the same tag"
[node name="TagOptions" type="ConfirmationDialog" parent="."]
margin_left = 8.0
margin_top = 8.0
margin_right = 392.0
margin_bottom = 164.0
[node name="GridContainer" type="GridContainer" parent="TagOptions"]
margin_left = 8.0
margin_top = 8.0
margin_right = 376.0
margin_bottom = 120.0
custom_constants/vseparation = 8
custom_constants/hseparation = 8
columns = 4
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NameLabel" type="Label" parent="TagOptions/GridContainer"]
margin_top = 5.0
margin_right = 42.0
margin_bottom = 19.0
text = "Name:"
[node name="NameLineEdit" type="LineEdit" parent="TagOptions/GridContainer"]
margin_left = 50.0
margin_right = 124.0
margin_bottom = 24.0
caret_blink = true
caret_blink_speed = 0.5
[node name="ColorLabel" type="Label" parent="TagOptions/GridContainer"]
margin_left = 132.0
margin_top = 5.0
margin_right = 169.0
margin_bottom = 19.0
text = "Color:"
[node name="ColorPickerButton" type="ColorPickerButton" parent="TagOptions/GridContainer"]
margin_left = 177.0
margin_right = 251.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
color = Color( 1, 0, 0, 1 )
[node name="FromLabel" type="Label" parent="TagOptions/GridContainer"]
margin_top = 37.0
margin_right = 42.0
margin_bottom = 51.0
text = "From:"
[node name="FromSpinBox" type="SpinBox" parent="TagOptions/GridContainer"]
margin_left = 50.0
margin_top = 32.0
margin_right = 124.0
margin_bottom = 56.0
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
[node name="ToLabel" type="Label" parent="TagOptions/GridContainer"]
margin_left = 132.0
margin_top = 37.0
margin_right = 169.0
margin_bottom = 51.0
text = "To:"
[node name="ToSpinBox" type="SpinBox" parent="TagOptions/GridContainer"]
margin_left = 177.0
margin_top = 32.0
margin_right = 251.0
margin_bottom = 56.0
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
[connection signal="about_to_show" from="." to="." method="_on_FrameTagDialog_about_to_show"]
[connection signal="popup_hide" from="." to="." method="_on_FrameTagDialog_popup_hide"]
[connection signal="pressed" from="VBoxContainer/ScrollContainer/VBoxTagContainer/AddTag" to="." method="_on_AddTag_pressed"]
[connection signal="toggled" from="VBoxContainer/PlayOnlyTags" to="." method="_on_PlayOnlyTags_toggled"]
[connection signal="confirmed" from="TagOptions" to="." method="_on_TagOptions_confirmed"]
[connection signal="custom_action" from="TagOptions" to="." method="_on_TagOptions_custom_action"]
[connection signal="popup_hide" from="TagOptions" to="." method="_on_TagOptions_popup_hide"]

100
src/UI/Dialogs/HSVDialog.gd Normal file
View file

@ -0,0 +1,100 @@
extends WindowDialog
var current_layer : Image
var preview_image : Image
var preview_texture : ImageTexture
onready var hue_slider = $MarginContainer/VBoxContainer/HBoxContainer/Sliders/Hue
onready var sat_slider = $MarginContainer/VBoxContainer/HBoxContainer/Sliders/Saturation
onready var val_slider = $MarginContainer/VBoxContainer/HBoxContainer/Sliders/Value
onready var hue_spinbox = $MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Hue
onready var sat_spinbox = $MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Saturation
onready var val_spinbox = $MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Value
onready var preview = $MarginContainer/VBoxContainer/TextureRect
func _ready() -> void:
current_layer = Image.new()
preview_image = Image.new()
preview_texture = ImageTexture.new()
preview_texture.flags = 0
func _on_HSVDialog_about_to_show() -> void:
current_layer = Global.canvas.layers[Global.current_layer][0]
preview_image.copy_from(current_layer)
update_preview()
func _on_Cancel_pressed() -> void:
visible = false
reset()
func _on_Apply_pressed() -> void:
Global.canvas.handle_undo("Draw")
Global.canvas.adjust_hsv(current_layer,0,hue_slider.value)
Global.canvas.adjust_hsv(current_layer,1,sat_slider.value)
Global.canvas.adjust_hsv(current_layer,2,val_slider.value)
Global.canvas.update_texture(Global.current_layer)
Global.canvas.handle_redo("Draw")
reset()
visible = false
func reset() -> void:
disconnect_signals()
hue_slider.value = 0
sat_slider.value = 0
val_slider.value = 0
hue_spinbox.value = 0
sat_spinbox.value = 0
val_spinbox.value = 0
reconnect_signals()
func update_preview() -> void:
preview_image.copy_from(current_layer)
Global.canvas.adjust_hsv(preview_image,0,hue_slider.value)
Global.canvas.adjust_hsv(preview_image,1,sat_slider.value)
Global.canvas.adjust_hsv(preview_image,2,val_slider.value)
preview_texture.create_from_image(preview_image, 0)
preview.texture = preview_texture
func disconnect_signals() -> void:
hue_slider.disconnect("value_changed",self,"_on_Hue_value_changed")
sat_slider.disconnect("value_changed",self,"_on_Saturation_value_changed")
val_slider.disconnect("value_changed",self,"_on_Value_value_changed")
hue_spinbox.disconnect("value_changed",self,"_on_Hue_value_changed")
sat_spinbox.disconnect("value_changed",self,"_on_Saturation_value_changed")
val_spinbox.disconnect("value_changed",self,"_on_Value_value_changed")
func reconnect_signals() -> void:
hue_slider.connect("value_changed",self,"_on_Hue_value_changed")
sat_slider.connect("value_changed",self,"_on_Saturation_value_changed")
val_slider.connect("value_changed",self,"_on_Value_value_changed")
hue_spinbox.connect("value_changed",self,"_on_Hue_value_changed")
sat_spinbox.connect("value_changed",self,"_on_Saturation_value_changed")
val_spinbox.connect("value_changed",self,"_on_Value_value_changed")
func _on_Hue_value_changed(value : float) -> void:
hue_spinbox.value = value
hue_slider.value = value
update_preview()
func _on_Saturation_value_changed(value : float) -> void:
sat_spinbox.value = value
sat_slider.value = value
update_preview()
func _on_Value_value_changed(value : float) -> void:
val_spinbox.value = value
val_slider.value = value
update_preview()

View file

@ -0,0 +1,168 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Dialogs/HSVDialog.gd" type="Script" id=1]
[node name="HSVDialog" type="WindowDialog"]
margin_left = 1.0
margin_top = -1.0
margin_right = 464.0
margin_bottom = 318.0
window_title = "Adjust HSV"
resizable = true
script = ExtResource( 1 )
[node name="MarginContainer" type="MarginContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
custom_constants/margin_right = 5
custom_constants/margin_top = 5
custom_constants/margin_left = 5
custom_constants/margin_bottom = 5
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"]
margin_left = 5.0
margin_top = 5.0
margin_right = 458.0
margin_bottom = 314.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="TextureRect" parent="MarginContainer/VBoxContainer"]
margin_right = 453.0
margin_bottom = 197.0
size_flags_vertical = 3
expand = true
stretch_mode = 6
[node name="HBoxContainer" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
margin_top = 201.0
margin_right = 453.0
margin_bottom = 285.0
custom_constants/separation = 10
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Names" type="VBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer"]
margin_right = 82.0
margin_bottom = 84.0
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.9
custom_constants/separation = 8
[node name="Hue" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/Names"]
margin_right = 82.0
margin_bottom = 14.0
text = "Hue"
align = 2
[node name="Saturation" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/Names"]
margin_top = 22.0
margin_right = 82.0
margin_bottom = 36.0
text = "Saturation"
align = 2
[node name="Value" type="Label" parent="MarginContainer/VBoxContainer/HBoxContainer/Names"]
margin_top = 44.0
margin_right = 82.0
margin_bottom = 58.0
text = "Value"
align = 2
[node name="Sliders" type="VBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer"]
margin_left = 92.0
margin_right = 368.0
margin_bottom = 84.0
size_flags_horizontal = 3
size_flags_stretch_ratio = 3.0
custom_constants/separation = 7
[node name="Hue" type="HSlider" parent="MarginContainer/VBoxContainer/HBoxContainer/Sliders"]
margin_right = 276.0
margin_bottom = 16.0
mouse_default_cursor_shape = 2
min_value = -180.0
max_value = 180.0
[node name="Saturation" type="HSlider" parent="MarginContainer/VBoxContainer/HBoxContainer/Sliders"]
margin_top = 23.0
margin_right = 276.0
margin_bottom = 39.0
mouse_default_cursor_shape = 2
min_value = -100.0
[node name="Value" type="HSlider" parent="MarginContainer/VBoxContainer/HBoxContainer/Sliders"]
margin_top = 46.0
margin_right = 276.0
margin_bottom = 62.0
mouse_default_cursor_shape = 2
min_value = -100.0
[node name="TextBoxes" type="VBoxContainer" parent="MarginContainer/VBoxContainer/HBoxContainer"]
margin_left = 378.0
margin_right = 452.0
margin_bottom = 84.0
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.0
custom_constants/separation = 6
[node name="Hue" type="SpinBox" parent="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes"]
margin_right = 74.0
margin_bottom = 24.0
mouse_default_cursor_shape = 1
min_value = -180.0
max_value = 180.0
[node name="Saturation" type="SpinBox" parent="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes"]
margin_top = 30.0
margin_right = 74.0
margin_bottom = 54.0
mouse_default_cursor_shape = 1
min_value = -100.0
[node name="Value" type="SpinBox" parent="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes"]
margin_top = 60.0
margin_right = 74.0
margin_bottom = 84.0
mouse_default_cursor_shape = 1
min_value = -100.0
[node name="HBoxContainer2" type="HBoxContainer" parent="MarginContainer/VBoxContainer"]
margin_top = 289.0
margin_right = 453.0
margin_bottom = 309.0
custom_constants/separation = 16
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Apply" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer2"]
margin_right = 218.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Apply"
[node name="Cancel" type="Button" parent="MarginContainer/VBoxContainer/HBoxContainer2"]
margin_left = 234.0
margin_right = 453.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Cancel"
[connection signal="about_to_show" from="." to="." method="_on_HSVDialog_about_to_show"]
[connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/Sliders/Hue" to="." method="_on_Hue_value_changed"]
[connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/Sliders/Saturation" to="." method="_on_Saturation_value_changed"]
[connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/Sliders/Value" to="." method="_on_Value_value_changed"]
[connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Hue" to="." method="_on_Hue_value_changed"]
[connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Saturation" to="." method="_on_Saturation_value_changed"]
[connection signal="value_changed" from="MarginContainer/VBoxContainer/HBoxContainer/TextBoxes/Value" to="." method="_on_Value_value_changed"]
[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer2/Apply" to="." method="_on_Apply_pressed"]
[connection signal="pressed" from="MarginContainer/VBoxContainer/HBoxContainer2/Cancel" to="." method="_on_Cancel_pressed"]

View file

@ -0,0 +1,146 @@
extends FileDialog
var new_frame := true
var import_spritesheet := false
var spritesheet_horizontal := 1
var spritesheet_vertical := 1
func _ready() -> void:
var children := []
for i in range(get_child_count()):
if i > 7:
children.append(get_child(i))
for child in children:
remove_child(child)
get_vbox().add_child(child)
func _on_ImportAsNewFrame_pressed() -> void:
new_frame = !new_frame
func _on_ImportSpritesheet_pressed() -> void:
import_spritesheet = !import_spritesheet
var spritesheet_container = Global.find_node_by_name(self, "Spritesheet")
spritesheet_container.visible = import_spritesheet
func _on_HorizontalFrames_value_changed(value) -> void:
spritesheet_horizontal = value
func _on_VerticalFrames_value_changed(value) -> void:
spritesheet_vertical = value
func _on_ImportSprites_files_selected(paths : PoolStringArray) -> void:
Global.control.opensprite_file_selected = true
if !new_frame: # If we're not adding a new frame, delete the previous
Global.clear_canvases()
var first_path : String = paths[0]
var i : int = Global.canvases.size()
if !import_spritesheet:
# Find the biggest image and let it handle the camera zoom options
var max_size : Vector2
var biggest_canvas : Canvas
for path in paths:
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()
continue
var canvas : Canvas = load("res://src/Canvas.tscn").instance()
canvas.size = image.get_size()
image.convert(Image.FORMAT_RGBA8)
image.lock()
var tex := ImageTexture.new()
tex.create_from_image(image, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([image, tex, 1])
for _i in range(1, Global.layers.size()):
var empty_sprite := Image.new()
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
empty_sprite.fill(Color(0, 0, 0, 0))
empty_sprite.lock()
var empty_tex := ImageTexture.new()
empty_tex.create_from_image(empty_sprite, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([empty_sprite, empty_tex, 1])
canvas.frame = i
Global.canvases.append(canvas)
Global.canvas_parent.add_child(canvas)
canvas.visible = false
if path == paths[0]: # If it's the first file
max_size = canvas.size
biggest_canvas = canvas
else:
if canvas.size > max_size:
biggest_canvas = canvas
i += 1
if biggest_canvas:
biggest_canvas.camera_zoom()
else:
var image := Image.new()
var err := image.load(first_path)
if err != OK: # An error occured
var file_name : String = first_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()
return
spritesheet_horizontal = min(spritesheet_horizontal, image.get_size().x)
spritesheet_vertical = min(spritesheet_vertical, image.get_size().y)
var frame_width := image.get_size().x / spritesheet_horizontal
var frame_height := image.get_size().y / spritesheet_vertical
for yy in range(spritesheet_vertical):
for xx in range(spritesheet_horizontal):
var canvas : Canvas = load("res://src/Canvas.tscn").instance()
var cropped_image := Image.new()
cropped_image = image.get_rect(Rect2(frame_width * xx, frame_height * yy, frame_width, frame_height))
canvas.size = cropped_image.get_size()
cropped_image.convert(Image.FORMAT_RGBA8)
cropped_image.lock()
var tex := ImageTexture.new()
tex.create_from_image(cropped_image, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([cropped_image, tex, 1])
for _i in range(1, Global.layers.size()):
var empty_sprite := Image.new()
empty_sprite.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8)
empty_sprite.fill(Color(0, 0, 0, 0))
empty_sprite.lock()
var empty_tex := ImageTexture.new()
empty_tex.create_from_image(empty_sprite, 0)
# Store [Image, ImageTexture, Opacity]
canvas.layers.append([empty_sprite, empty_tex, 1])
canvas.frame = i
Global.canvases.append(canvas)
Global.canvas_parent.add_child(canvas)
canvas.visible = false
i += 1
Global.canvases[Global.canvases.size() - 1].camera_zoom()
Global.canvases = Global.canvases # Just to call Global.canvases_changed
Global.current_frame = i - 1
Global.canvas = Global.canvases[Global.canvases.size() - 1]
Global.canvas.visible = true
Global.window_title = first_path.get_file() + " (" + tr("imported") + ") - Pixelorama"

View file

@ -0,0 +1,78 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Dialogs/ImportSprites.gd" type="Script" id=1]
[node name="ImportSprites" type="FileDialog"]
margin_right = 515.0
margin_bottom = 348.0
window_title = "Open File(s)"
resizable = true
mode = 1
access = 2
filters = PoolStringArray( "*.bmp ; BMP Image", "*.hdr ; Radiance HDR Image", "*.jpg,*.jpeg ; JPEG Image", "*.png ; PNG Image", "*.svg ; SVG Image", "*.tga ; TGA Image", "*.webp ; WebP Image" )
current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama"
current_path = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/"
script = ExtResource( 1 )
[node name="HBoxContainer2" type="HBoxContainer" parent="."]
margin_left = 8.0
margin_top = 8.0
margin_right = 507.0
margin_bottom = 312.0
[node name="ImportAsNewFrame" type="CheckBox" parent="HBoxContainer2"]
margin_right = 161.0
margin_bottom = 304.0
mouse_default_cursor_shape = 2
pressed = true
text = "Import as new frame"
[node name="ImportSpritesheet" type="CheckBox" parent="HBoxContainer2"]
margin_left = 165.0
margin_right = 343.0
margin_bottom = 304.0
mouse_default_cursor_shape = 2
text = "Import as a spritesheet"
[node name="Spritesheet" type="HBoxContainer" parent="."]
visible = false
margin_left = 8.0
margin_top = 8.0
margin_right = 507.0
margin_bottom = 312.0
[node name="Label" type="Label" parent="Spritesheet"]
margin_top = 1.0
margin_right = 101.0
margin_bottom = 16.0
text = "Horizontal frames:"
[node name="HorizontalFrames" type="SpinBox" parent="Spritesheet"]
margin_left = 105.0
margin_right = 159.0
margin_bottom = 17.0
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
[node name="Label2" type="Label" parent="Spritesheet"]
margin_left = 163.0
margin_top = 1.0
margin_right = 248.0
margin_bottom = 16.0
text = "Vertical frames:"
[node name="VerticalFrames" type="SpinBox" parent="Spritesheet"]
margin_left = 252.0
margin_right = 306.0
margin_bottom = 17.0
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
[connection signal="files_selected" from="." to="." method="_on_ImportSprites_files_selected"]
[connection signal="pressed" from="HBoxContainer2/ImportAsNewFrame" to="." method="_on_ImportAsNewFrame_pressed"]
[connection signal="pressed" from="HBoxContainer2/ImportSpritesheet" to="." method="_on_ImportSpritesheet_pressed"]
[connection signal="value_changed" from="Spritesheet/HorizontalFrames" to="." method="_on_HorizontalFrames_value_changed"]
[connection signal="value_changed" from="Spritesheet/VerticalFrames" to="." method="_on_VerticalFrames_value_changed"]

View file

@ -0,0 +1,7 @@
[gd_scene format=2]
[node name="NoProjectEditedOrCreatedAlertDialog" type="AcceptDialog"]
dialog_text = "You haven't saved or opened any project in Pixelorama yet!"
__meta__ = {
"_edit_use_anchors_": false
}

View file

@ -0,0 +1,7 @@
[gd_scene format=2]
[node name="OpenLastProjectAlertDialog" type="AcceptDialog"]
margin_right = 209.0
margin_bottom = 58.0
window_title = "Alarm!"
dialog_text = "Cannot find last project file."

View file

@ -0,0 +1,146 @@
extends ConfirmationDialog
func _ready() -> void:
$OptionsContainer/OutlineColor.get_picker().presets_visible = false
func _on_OutlineDialog_confirmed() -> void:
var outline_color : Color = $OptionsContainer/OutlineColor.color
var thickness : int = $OptionsContainer/ThickValue.value
var diagonal : bool = $OptionsContainer/DiagonalCheckBox.pressed
var inside_image : bool = $OptionsContainer/InsideImageCheckBox.pressed
var image : Image = Global.canvas.layers[Global.current_layer][0]
if image.is_invisible():
return
var new_image := Image.new()
new_image.copy_from(image)
new_image.lock()
Global.canvas.handle_undo("Draw")
for xx in image.get_size().x:
for yy in image.get_size().y:
var pos = Vector2(xx, yy)
var current_pixel := image.get_pixelv(pos)
if current_pixel.a == 0:
continue
for i in range(1, thickness + 1):
if inside_image:
var outline_pos : Vector2 = pos + Vector2.LEFT # Left
if outline_pos.x < 0 || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + Vector2.RIGHT * (i - 1)
if new_pos.x < Global.canvas.size.x:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + Vector2.RIGHT # Right
if outline_pos.x >= Global.canvas.size.x || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + Vector2.LEFT * (i - 1)
if new_pos.x >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + Vector2.UP # Up
if outline_pos.y < 0 || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + Vector2.DOWN * (i - 1)
if new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + Vector2.DOWN # Down
if outline_pos.y >= Global.canvas.size.y || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + Vector2.UP * (i - 1)
if new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
if diagonal:
outline_pos = pos + (Vector2.LEFT + Vector2.UP) # Top left
if (outline_pos.x < 0 && outline_pos.y < 0) || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + (Vector2.RIGHT + Vector2.DOWN) * (i - 1)
if new_pos.x < Global.canvas.size.x && new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + (Vector2.LEFT + Vector2.DOWN) # Bottom left
if (outline_pos.x < 0 && outline_pos.y >= Global.canvas.size.y) || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + (Vector2.RIGHT + Vector2.UP) * (i - 1)
if new_pos.x < Global.canvas.size.x && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + (Vector2.RIGHT + Vector2.UP) # Top right
if (outline_pos.x >= Global.canvas.size.x && outline_pos.y < 0) || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + (Vector2.LEFT + Vector2.DOWN) * (i - 1)
if new_pos.x >= 0 && new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + (Vector2.RIGHT + Vector2.DOWN) # Bottom right
if (outline_pos.x >= Global.canvas.size.x && outline_pos.y >= Global.canvas.size.y) || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + (Vector2.LEFT + Vector2.UP) * (i - 1)
if new_pos.x >= 0 && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color)
else:
var new_pos : Vector2 = pos + Vector2.LEFT * i # Left
if new_pos.x >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.RIGHT * i # Right
if new_pos.x < Global.canvas.size.x:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.UP * i # Up
if new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.DOWN * i # Down
if new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
if diagonal:
new_pos = pos + (Vector2.LEFT + Vector2.UP) * i # Top left
if new_pos.x >= 0 && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + (Vector2.LEFT + Vector2.DOWN) * i # Bottom left
if new_pos.x >= 0 && new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + (Vector2.RIGHT + Vector2.UP) * i # Top right
if new_pos.x < Global.canvas.size.x && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + (Vector2.RIGHT + Vector2.DOWN) * i # Bottom right
if new_pos.x < Global.canvas.size.x && new_pos.y < Global.canvas.size.y:
var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color)
image.copy_from(new_image)
Global.canvas.handle_redo("Draw")

View file

@ -0,0 +1,70 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Dialogs/OutlineDialog.gd" type="Script" id=1]
[node name="OutlineDialog" type="ConfirmationDialog"]
visible = true
margin_right = 200.0
margin_bottom = 70.0
script = ExtResource( 1 )
[node name="OptionsContainer" type="GridContainer" parent="."]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -121.0
margin_top = -52.0
margin_right = 121.0
margin_bottom = 24.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="ThickLabel" type="Label" parent="OptionsContainer"]
margin_top = 5.0
margin_right = 90.0
margin_bottom = 19.0
text = "Thickness:"
[node name="ThickValue" type="SpinBox" parent="OptionsContainer"]
margin_left = 94.0
margin_right = 242.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 1.0
suffix = "px"
[node name="OutlineColorLabel" type="Label" parent="OptionsContainer"]
margin_top = 31.0
margin_right = 90.0
margin_bottom = 45.0
text = "Fill with color:"
[node name="OutlineColor" type="ColorPickerButton" parent="OptionsContainer"]
margin_left = 94.0
margin_top = 28.0
margin_right = 242.0
margin_bottom = 48.0
rect_min_size = Vector2( 64, 20 )
color = Color( 1, 0, 0, 1 )
[node name="DiagonalCheckBox" type="CheckBox" parent="OptionsContainer"]
margin_top = 52.0
margin_right = 90.0
margin_bottom = 76.0
mouse_default_cursor_shape = 2
text = "Diagonal"
[node name="InsideImageCheckBox" type="CheckBox" parent="OptionsContainer"]
margin_left = 94.0
margin_top = 52.0
margin_right = 242.0
margin_bottom = 76.0
mouse_default_cursor_shape = 2
text = "Place inside image"
[connection signal="confirmed" from="." to="." method="_on_OutlineDialog_confirmed"]

View file

@ -0,0 +1,555 @@
extends AcceptDialog
onready var tree : Tree = $HSplitContainer/Tree
onready var right_side : VBoxContainer = $HSplitContainer/ScrollContainer/VBoxContainer
onready var general = $HSplitContainer/ScrollContainer/VBoxContainer/General
onready var languages = $HSplitContainer/ScrollContainer/VBoxContainer/Languages
onready var themes = $HSplitContainer/ScrollContainer/VBoxContainer/Themes
onready var canvas = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas
onready var image = $HSplitContainer/ScrollContainer/VBoxContainer/Image
onready var shortcuts = $HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts
onready var open_last_project_button = $HSplitContainer/ScrollContainer/VBoxContainer/General/OpenLastProject
onready var smooth_zoom_button = $HSplitContainer/ScrollContainer/VBoxContainer/General/SmoothZoom
onready var sensitivity_option = $HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity/PressureSensitivityOptionButton
onready var left_tool_icon = $HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftToolIconCheckbox
onready var right_tool_icon = $HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightToolIconCheckbox
onready var default_width_value = $HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultWidth
onready var default_height_value = $HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultHeight
onready var default_fill_color = $HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/DefaultFillColor
onready var grid_width_value = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridWidthValue
onready var grid_height_value = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridHeightValue
onready var grid_color = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridColor
onready var guide_color = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions/GuideColor
onready var checker_size_value = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerSizeValue
onready var checker_color_1 = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor1
onready var checker_color_2 = $HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor2
# Shortcuts
onready var theme_font_color : Color = $Popups/ShortcutSelector/EnteredShortcut.get_color("font_color")
var default_shortcuts_preset := {}
var custom_shortcuts_preset := {}
var action_being_edited := ""
var shortcut_already_assigned = false
var old_input_event : InputEventKey
var new_input_event : InputEventKey
func _ready() -> void:
# Disable input until the shortcut selector is displayed
set_process_input(false)
# Replace OK with Close since preference changes are being applied immediately, not after OK confirmation
get_ok().text = tr("Close")
for child in languages.get_children():
if child is Button:
child.connect("pressed", self, "_on_Language_pressed", [child])
child.hint_tooltip = child.name
for child in themes.get_children():
if child is Button:
child.connect("pressed", self, "_on_Theme_pressed", [child])
if Global.config_cache.has_section_key("preferences", "theme"):
var theme_id = Global.config_cache.get_value("preferences", "theme")
change_theme(theme_id)
themes.get_child(theme_id).pressed = true
else:
change_theme(0)
themes.get_child(0).pressed = true
# Set default values for General options
if Global.config_cache.has_section_key("preferences", "open_last_project"):
Global.open_last_project = Global.config_cache.get_value("preferences", "open_last_project")
open_last_project_button.pressed = Global.open_last_project
if Global.config_cache.has_section_key("preferences", "smooth_zoom"):
Global.smooth_zoom = Global.config_cache.get_value("preferences", "smooth_zoom")
smooth_zoom_button.pressed = Global.smooth_zoom
if Global.config_cache.has_section_key("preferences", "pressure_sensitivity"):
Global.pressure_sensitivity_mode = Global.config_cache.get_value("preferences", "pressure_sensitivity")
sensitivity_option.selected = Global.pressure_sensitivity_mode
if Global.config_cache.has_section_key("preferences", "show_left_tool_icon"):
Global.show_left_tool_icon = Global.config_cache.get_value("preferences", "show_left_tool_icon")
left_tool_icon.pressed = Global.show_left_tool_icon
if Global.config_cache.has_section_key("preferences", "show_right_tool_icon"):
Global.show_right_tool_icon = Global.config_cache.get_value("preferences", "show_right_tool_icon")
right_tool_icon.pressed = Global.show_right_tool_icon
# Get autosave settings
if Global.config_cache.has_section_key("preferences", "autosave_interval"):
var autosave_interval = Global.config_cache.get_value("preferences", "autosave_interval")
OpenSave.set_autosave_interval(autosave_interval)
general.get_node("AutosaveInterval/AutosaveInterval").value = autosave_interval
if Global.config_cache.has_section_key("preferences", "enable_autosave"):
var enable_autosave = Global.config_cache.get_value("preferences", "enable_autosave")
OpenSave.toggle_autosave(enable_autosave)
general.get_node("EnableAutosave").pressed = enable_autosave
# Set default values for Canvas options
if Global.config_cache.has_section_key("preferences", "grid_size"):
var grid_size = Global.config_cache.get_value("preferences", "grid_size")
Global.grid_width = int(grid_size.x)
Global.grid_height = int(grid_size.y)
grid_width_value.value = grid_size.x
grid_height_value.value = grid_size.y
if Global.config_cache.has_section_key("preferences", "grid_color"):
Global.grid_color = Global.config_cache.get_value("preferences", "grid_color")
grid_color.color = Global.grid_color
if Global.config_cache.has_section_key("preferences", "checker_size"):
var checker_size = Global.config_cache.get_value("preferences", "checker_size")
Global.checker_size = int(checker_size)
checker_size_value.value = checker_size
if Global.config_cache.has_section_key("preferences", "checker_color_1"):
Global.checker_color_1 = Global.config_cache.get_value("preferences", "checker_color_1")
checker_color_1.color = Global.checker_color_1
if Global.config_cache.has_section_key("preferences", "checker_color_2"):
Global.checker_color_2 = Global.config_cache.get_value("preferences", "checker_color_2")
checker_color_2.color = Global.checker_color_2
Global.transparent_checker._ready()
if Global.config_cache.has_section_key("preferences", "guide_color"):
Global.guide_color = Global.config_cache.get_value("preferences", "guide_color")
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.default_color = Global.guide_color
guide_color.color = Global.guide_color
# Set default values for Image
if Global.config_cache.has_section_key("preferences", "default_width"):
var default_width = Global.config_cache.get_value("preferences", "default_width")
Global.default_image_width = int(default_width)
default_width_value.value = Global.default_image_width
if Global.config_cache.has_section_key("preferences", "default_height"):
var default_height = Global.config_cache.get_value("preferences", "default_height")
Global.default_image_height = int(default_height)
default_height_value.value = Global.default_image_height
if Global.config_cache.has_section_key("preferences", "default_fill_color"):
var fill_color = Global.config_cache.get_value("preferences", "default_fill_color")
Global.default_fill_color = fill_color
default_fill_color.color = Global.default_fill_color
guide_color.get_picker().presets_visible = false
grid_color.get_picker().presets_visible = false
checker_color_1.get_picker().presets_visible = false
checker_color_2.get_picker().presets_visible = false
default_fill_color.get_picker().presets_visible = false
# Get default preset for shortcuts from project input map
# Buttons in shortcuts selector should be called the same as actions
for shortcut_grid_item in shortcuts.get_node("Shortcuts").get_children():
if shortcut_grid_item is Button:
var input_events = InputMap.get_action_list(shortcut_grid_item.name)
if input_events.size() > 1:
printerr("Every shortcut action should have just one input event assigned in input map")
shortcut_grid_item.text = (input_events[0] as InputEventKey).as_text()
shortcut_grid_item.connect("pressed", self, "_on_Shortcut_button_pressed", [shortcut_grid_item])
default_shortcuts_preset[shortcut_grid_item.name] = input_events[0]
# Load custom shortcuts from the config file
custom_shortcuts_preset = default_shortcuts_preset.duplicate()
for action in default_shortcuts_preset:
var saved_input_event = Global.config_cache.get_value("shortcuts", action, 0)
if saved_input_event is InputEventKey:
custom_shortcuts_preset[action] = saved_input_event
var shortcuts_preset = Global.config_cache.get_value("shortcuts", "shortcuts_preset", 0)
shortcuts.get_node("HBoxContainer/PresetOptionButton").select(shortcuts_preset)
_on_PresetOptionButton_item_selected(shortcuts_preset)
func _input(event : InputEvent) -> void:
if event is InputEventKey:
if event.pressed:
if event.scancode == KEY_ESCAPE:
$Popups/ShortcutSelector.hide()
else:
# Check if shortcut was already used
for action in InputMap.get_actions():
for input_event in InputMap.get_action_list(action):
if input_event is InputEventKey:
if OS.get_scancode_string(input_event.get_scancode_with_modifiers()) == OS.get_scancode_string(event.get_scancode_with_modifiers()):
$Popups/ShortcutSelector/EnteredShortcut.text = tr("Already assigned")
$Popups/ShortcutSelector/EnteredShortcut.add_color_override("font_color", Color.crimson)
get_tree().set_input_as_handled()
shortcut_already_assigned = true
return
# Store new shortcut
shortcut_already_assigned = false
old_input_event = InputMap.get_action_list(action_being_edited)[0]
new_input_event = event
$Popups/ShortcutSelector/EnteredShortcut.text = OS.get_scancode_string(event.get_scancode_with_modifiers())
$Popups/ShortcutSelector/EnteredShortcut.add_color_override("font_color", theme_font_color)
get_tree().set_input_as_handled()
func _on_PreferencesDialog_about_to_show(changed_language := false) -> void:
var root := tree.create_item()
var general_button := tree.create_item(root)
var language_button := tree.create_item(root)
var theme_button := tree.create_item(root)
var canvas_button := tree.create_item(root)
var image_button := tree.create_item(root)
var shortcuts_button := tree.create_item(root)
general_button.set_text(0, " " + tr("General"))
# We use metadata to avoid being affected by translations
general_button.set_metadata(0, "General")
language_button.set_text(0, " " + tr("Language"))
language_button.set_metadata(0, "Language")
theme_button.set_text(0, " " + tr("Themes"))
theme_button.set_metadata(0, "Themes")
canvas_button.set_text(0, " " + tr("Canvas"))
canvas_button.set_metadata(0, "Canvas")
image_button.set_text(0, " " + tr("Image"))
image_button.set_metadata(0, "Image")
shortcuts_button.set_text(0, " " + tr("Shortcuts"))
shortcuts_button.set_metadata(0, "Shortcuts")
if changed_language:
language_button.select(0)
else:
general_button.select(0)
func _on_PreferencesDialog_popup_hide() -> void:
tree.clear()
func _on_Tree_item_selected() -> void:
for child in right_side.get_children():
child.visible = false
var selected : String = tree.get_selected().get_metadata(0)
if "General" in selected:
general.visible = true
elif "Language" in selected:
languages.visible = true
elif "Themes" in selected:
themes.visible = true
elif "Canvas" in selected:
canvas.visible = true
elif "Image" in selected:
image.visible = true
elif "Shortcuts" in selected:
shortcuts.visible = true
func _on_PressureSensitivityOptionButton_item_selected(id : int) -> void:
Global.pressure_sensitivity_mode = id
Global.config_cache.set_value("preferences", "pressure_sensitivity", id)
Global.config_cache.save("user://cache.ini")
func _on_SmoothZoom_pressed() -> void:
Global.smooth_zoom = !Global.smooth_zoom
Global.config_cache.set_value("preferences", "smooth_zoom", Global.smooth_zoom)
Global.config_cache.save("user://cache.ini")
func _on_Language_pressed(button : Button) -> void:
var index := 0
var i := -1
for child in languages.get_children():
if child is Button:
if child == button:
button.pressed = true
index = i
else:
child.pressed = false
i += 1
if index == -1:
TranslationServer.set_locale(OS.get_locale())
else:
TranslationServer.set_locale(Global.loaded_locales[index])
if "zh" in TranslationServer.get_locale():
Global.control.theme.default_font = preload("res://Assets/Fonts/CJK/NotoSansCJKtc-Regular.tres")
else:
Global.control.theme.default_font = preload("res://Assets/Fonts/Roboto-Regular.tres")
Global.config_cache.set_value("preferences", "locale", TranslationServer.get_locale())
Global.config_cache.save("user://cache.ini")
# Update Translations
Global.update_hint_tooltips()
_on_PreferencesDialog_popup_hide()
_on_PreferencesDialog_about_to_show(true)
func _on_Theme_pressed(button : Button) -> void:
var index := 0
var i := 0
for child in themes.get_children():
if child is Button:
if child == button:
button.pressed = true
index = i
else:
child.pressed = false
i += 1
change_theme(index)
Global.config_cache.set_value("preferences", "theme", index)
Global.config_cache.save("user://cache.ini")
func change_theme(ID : int) -> void:
var font = Global.control.theme.default_font
var main_theme
var top_menu_style
var ruler_style
if ID == 0: # Dark Theme
Global.theme_type = "Dark"
VisualServer.set_default_clear_color(Color(0.247059, 0.25098, 0.247059))
main_theme = preload("res://Assets/themes/dark/theme.tres")
top_menu_style = preload("res://Assets/themes/dark/top_menu_style.tres")
ruler_style = preload("res://Assets/themes/dark/ruler_style.tres")
elif ID == 1: # Gray Theme
Global.theme_type = "Dark"
VisualServer.set_default_clear_color(Color(0.301961, 0.301961, 0.301961))
main_theme = preload("res://Assets/themes/gray/theme.tres")
top_menu_style = preload("res://Assets/themes/gray/top_menu_style.tres")
ruler_style = preload("res://Assets/themes/dark/ruler_style.tres")
elif ID == 2: # Godot's Theme
Global.theme_type = "Dark"
VisualServer.set_default_clear_color(Color(0.27451, 0.278431, 0.305882))
main_theme = preload("res://Assets/themes/godot/theme.tres")
top_menu_style = preload("res://Assets/themes/godot/top_menu_style.tres")
ruler_style = preload("res://Assets/themes/godot/ruler_style.tres")
elif ID == 3: # Gold Theme
Global.theme_type = "Gold"
VisualServer.set_default_clear_color(Color(0.694118, 0.619608, 0.458824))
main_theme = preload("res://Assets/themes/gold/theme.tres")
top_menu_style = preload("res://Assets/themes/gold/top_menu_style.tres")
ruler_style = preload("res://Assets/themes/gold/ruler_style.tres")
elif ID == 4: # Light Theme
Global.theme_type = "Light"
VisualServer.set_default_clear_color(Color(0.705882, 0.705882, 0.705882))
main_theme = preload("res://Assets/themes/light/theme.tres")
top_menu_style = preload("res://Assets/themes/light/top_menu_style.tres")
ruler_style = preload("res://Assets/themes/light/ruler_style.tres")
Global.control.theme = main_theme
Global.control.theme.default_font = font
Global.top_menu_container.add_stylebox_override("panel", top_menu_style)
Global.horizontal_ruler.add_stylebox_override("normal", ruler_style)
Global.horizontal_ruler.add_stylebox_override("pressed", ruler_style)
Global.horizontal_ruler.add_stylebox_override("hover", ruler_style)
Global.horizontal_ruler.add_stylebox_override("focus", ruler_style)
Global.vertical_ruler.add_stylebox_override("normal", ruler_style)
Global.vertical_ruler.add_stylebox_override("pressed", ruler_style)
Global.vertical_ruler.add_stylebox_override("hover", ruler_style)
Global.vertical_ruler.add_stylebox_override("focus", ruler_style)
for button in get_tree().get_nodes_in_group("UIButtons"):
if button is TextureButton:
var last_backslash = button.texture_normal.resource_path.get_base_dir().find_last("/")
var button_category = button.texture_normal.resource_path.get_base_dir().right(last_backslash + 1)
var normal_file_name = button.texture_normal.resource_path.get_file()
button.texture_normal = load("res://Assets/Graphics/%s Themes/%s/%s" % [Global.theme_type, button_category, normal_file_name])
if button.texture_pressed:
var pressed_file_name = button.texture_pressed.resource_path.get_file()
button.texture_pressed = load("res://Assets/Graphics/%s Themes/%s/%s" % [Global.theme_type, button_category, pressed_file_name])
if button.texture_hover:
var hover_file_name = button.texture_hover.resource_path.get_file()
button.texture_hover = load("res://Assets/Graphics/%s Themes/%s/%s" % [Global.theme_type, button_category, hover_file_name])
if button.texture_disabled:
var disabled_file_name = button.texture_disabled.resource_path.get_file()
button.texture_disabled = load("res://Assets/Graphics/%s Themes/%s/%s" % [Global.theme_type, button_category, disabled_file_name])
elif button is Button:
var theme_type := Global.theme_type
if theme_type == "Gold":
theme_type = "Light"
var texture : TextureRect = button.get_child(0)
var last_backslash = texture.texture.resource_path.get_base_dir().find_last("/")
var button_category = texture.texture.resource_path.get_base_dir().right(last_backslash + 1)
var normal_file_name = texture.texture.resource_path.get_file()
texture.texture = load("res://Assets/Graphics/%s Themes/%s/%s" % [theme_type, button_category, normal_file_name])
# Make sure the frame text gets updated
Global.current_frame = Global.current_frame
$Popups/ShortcutSelector.theme = main_theme
func apply_shortcuts_preset(preset) -> void:
for action in preset:
var old_input_event : InputEventKey = InputMap.get_action_list(action)[0]
set_action_shortcut(action, old_input_event, preset[action])
shortcuts.get_node("Shortcuts/" + action).text = OS.get_scancode_string(preset[action].get_scancode_with_modifiers())
func toggle_shortcut_buttons(enabled : bool) -> void:
for shortcut_grid_item in shortcuts.get_node("Shortcuts").get_children():
if shortcut_grid_item is Button:
shortcut_grid_item.disabled = not enabled
if shortcut_grid_item.disabled:
shortcut_grid_item.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
else:
shortcut_grid_item.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND
func set_action_shortcut(action : String, old_input : InputEventKey, new_input : InputEventKey) -> void:
InputMap.action_erase_event(action, old_input)
InputMap.action_add_event(action, new_input)
Global.update_hint_tooltips()
# Set shortcut to switch colors button
if action == "switch_colors":
Global.color_switch_button.shortcut.shortcut = InputMap.get_action_list("switch_colors")[0]
func _on_GridWidthValue_value_changed(value : float) -> void:
Global.grid_width = value
Global.canvas.update()
Global.config_cache.set_value("preferences", "grid_size", Vector2(value, grid_height_value.value))
Global.config_cache.save("user://cache.ini")
func _on_GridHeightValue_value_changed(value : float) -> void:
Global.grid_height = value
Global.canvas.update()
Global.config_cache.set_value("preferences", "grid_size", Vector2(grid_width_value.value, value))
Global.config_cache.save("user://cache.ini")
func _on_GridColor_color_changed(color : Color) -> void:
Global.grid_color = color
Global.canvas.update()
Global.config_cache.set_value("preferences", "grid_color", color)
Global.config_cache.save("user://cache.ini")
func _on_CheckerSize_value_changed(value : float) -> void:
Global.checker_size = value
Global.transparent_checker._ready()
Global.config_cache.set_value("preferences", "checker_size", value)
Global.config_cache.save("user://cache.ini")
func _on_CheckerColor1_color_changed(color : Color) -> void:
Global.checker_color_1 = color
Global.transparent_checker._ready()
Global.config_cache.set_value("preferences", "checker_color_1", color)
Global.config_cache.save("user://cache.ini")
func _on_CheckerColor2_color_changed(color : Color) -> void:
Global.checker_color_2 = color
Global.transparent_checker._ready()
Global.config_cache.set_value("preferences", "checker_color_2", color)
Global.config_cache.save("user://cache.ini")
func _on_GuideColor_color_changed(color : Color) -> void:
Global.guide_color = color
for canvas in Global.canvases:
for guide in canvas.get_children():
if guide is Guide:
guide.default_color = color
Global.config_cache.set_value("preferences", "guide_color", color)
Global.config_cache.save("user://cache.ini")
func _on_ImageDefaultWidth_value_changed(value: float) -> void:
Global.default_image_width = value
Global.config_cache.set_value("preferences", "default_width", value)
Global.config_cache.save("user://cache.ini")
func _on_ImageDefaultHeight_value_changed(value: float) -> void:
Global.default_image_height = value
Global.config_cache.set_value("preferences", "default_height", value)
Global.config_cache.save("user://cache.ini")
func _on_DefaultBackground_color_changed(color: Color) -> void:
Global.default_fill_color = color
Global.config_cache.set_value("preferences", "default_fill_color", color)
Global.config_cache.save("user://cache.ini")
func _on_LeftIndicatorCheckbox_toggled(button_pressed : bool) -> void:
Global.left_square_indicator_visible = button_pressed
func _on_RightIndicatorCheckbox_toggled(button_pressed : bool) -> void:
Global.right_square_indicator_visible = button_pressed
func _on_LeftToolIconCheckbox_toggled(button_pressed : bool) -> void:
Global.show_left_tool_icon = button_pressed
Global.config_cache.set_value("preferences", "show_left_tool_icon", Global.show_left_tool_icon)
Global.config_cache.save("user://cache.ini")
func _on_RightToolIconCheckbox_toggled(button_pressed : bool) -> void:
Global.show_right_tool_icon = button_pressed
Global.config_cache.set_value("preferences", "show_right_tool_icon", Global.show_right_tool_icon)
Global.config_cache.save("user://cache.ini")
func _on_Shortcut_button_pressed(button : Button) -> void:
set_process_input(true)
action_being_edited = button.name
new_input_event = InputMap.get_action_list(button.name)[0]
shortcut_already_assigned = true
$Popups/ShortcutSelector.popup_centered()
func _on_ShortcutSelector_popup_hide() -> void:
set_process_input(false)
$Popups/ShortcutSelector/EnteredShortcut.text = ""
func _on_PresetOptionButton_item_selected(id : int) -> void:
# Only custom preset which is modifiable
toggle_shortcut_buttons(true if id == 1 else false)
match id:
0:
apply_shortcuts_preset(default_shortcuts_preset)
1:
apply_shortcuts_preset(custom_shortcuts_preset)
Global.config_cache.set_value("shortcuts", "shortcuts_preset", id)
Global.config_cache.save("user://cache.ini")
func _on_ShortcutSelector_confirmed() -> void:
if not shortcut_already_assigned:
set_action_shortcut(action_being_edited, old_input_event, new_input_event)
custom_shortcuts_preset[action_being_edited] = new_input_event
Global.config_cache.set_value("shortcuts", action_being_edited, new_input_event)
Global.config_cache.save("user://cache.ini")
shortcuts.get_node("Shortcuts/" + action_being_edited).text = OS.get_scancode_string(new_input_event.get_scancode_with_modifiers())
$Popups/ShortcutSelector.hide()
func _on_OpenLastProject_pressed() -> void:
Global.open_last_project = !Global.open_last_project
Global.config_cache.set_value("preferences", "open_last_project", Global.open_last_project)
Global.config_cache.save("user://cache.ini")
func _on_EnableAutosave_toggled(button_pressed : bool) -> void:
OpenSave.toggle_autosave(button_pressed)
Global.config_cache.set_value("preferences", "enable_autosave", button_pressed)
Global.config_cache.save("user://cache.ini")
func _on_AutosaveInterval_value_changed(value : float) -> void:
OpenSave.set_autosave_interval(value)
Global.config_cache.set_value("preferences", "autosave_interval", value)
Global.config_cache.save("user://cache.ini")

View file

@ -0,0 +1,875 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://src/UI/Dialogs/PreferencesDialog.gd" type="Script" id=1]
[ext_resource path="res://Assets/Fonts/Roboto-Regular.tres" type="DynamicFont" id=2]
[ext_resource path="res://Assets/Fonts/CJK/NotoSansCJKtc-Regular.tres" type="DynamicFont" id=3]
[node name="PreferencesDialog" type="AcceptDialog"]
margin_left = -3.0
margin_top = 9.0
margin_right = 419.0
margin_bottom = 1163.0
rect_min_size = Vector2( 422, 340 )
window_title = "Preferences"
resizable = true
script = ExtResource( 1 )
__meta__ = {
"_edit_horizontal_guides_": [ ],
"_edit_use_anchors_": false,
"_edit_vertical_guides_": [ ]
}
[node name="HSplitContainer" type="HSplitContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 8.0
margin_top = 8.0
margin_right = -8.0
margin_bottom = -36.0
size_flags_horizontal = 3
custom_constants/autohide = 0
split_offset = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Tree" type="Tree" parent="HSplitContainer"]
margin_right = 86.0
margin_bottom = 1110.0
rect_min_size = Vector2( 85, 0 )
custom_constants/item_margin = -2
hide_root = true
[node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer"]
margin_left = 98.0
margin_right = 406.0
margin_bottom = 1110.0
rect_min_size = Vector2( 100, 0 )
size_flags_horizontal = 3
[node name="VBoxContainer" type="VBoxContainer" parent="HSplitContainer/ScrollContainer"]
margin_right = 308.0
margin_bottom = 1230.0
size_flags_horizontal = 3
[node name="General" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_right = 306.0
margin_bottom = 180.0
[node name="SmoothZoom" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_right = 306.0
margin_bottom = 24.0
hint_tooltip = "Adds a smoother transition when zooming in or out"
mouse_default_cursor_shape = 2
pressed = true
text = "Smooth Zoom"
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 28.0
margin_right = 306.0
margin_bottom = 32.0
[node name="GridContainer" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 36.0
margin_right = 306.0
margin_bottom = 88.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="LeftIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_right = 147.0
margin_bottom = 24.0
hint_tooltip = "Show left mouse pixel indicator or brush on the canvas when drawing"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
pressed = true
text = "Left pixel indicator"
[node name="RightIndicatorCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_left = 151.0
margin_right = 306.0
margin_bottom = 24.0
hint_tooltip = "Show right mouse pixel indicator or brush on the canvas when drawing"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Right pixel indicator"
[node name="LeftToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_top = 28.0
margin_right = 147.0
margin_bottom = 52.0
hint_tooltip = "Displays an icon of the selected left tool next to the cursor on the canvas"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
pressed = true
text = "Show left tool icon"
[node name="RightToolIconCheckbox" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer"]
margin_left = 151.0
margin_top = 28.0
margin_right = 306.0
margin_bottom = 52.0
hint_tooltip = "Displays an icon of the selected right tool next to the cursor on the canvas"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
pressed = true
text = "Show right tool icon"
[node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 92.0
margin_right = 306.0
margin_bottom = 96.0
[node name="PressureSentivity" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
visible = false
margin_top = 116.0
margin_right = 334.0
margin_bottom = 136.0
[node name="PressureSensitivityLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity"]
margin_top = 3.0
margin_right = 173.0
margin_bottom = 17.0
text = "Tablet pressure sensitivity:"
[node name="PressureSensitivityOptionButton" type="OptionButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity"]
margin_left = 177.0
margin_right = 334.0
margin_bottom = 20.0
text = "Affect Brush's Alpha"
items = [ "None", null, false, 0, null, "Affect Brush's Alpha", null, false, 1, null ]
selected = 1
[node name="OpenLastProject" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 100.0
margin_right = 306.0
margin_bottom = 124.0
hint_tooltip = "Opens last opened project on startup"
mouse_default_cursor_shape = 2
pressed = true
text = "Open last project on startup"
[node name="EnableAutosave" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 128.0
margin_right = 306.0
margin_bottom = 152.0
mouse_default_cursor_shape = 2
text = "Enable autosave"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AutosaveInterval" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/General"]
margin_top = 156.0
margin_right = 306.0
margin_bottom = 180.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AutosaveIntervalLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval"]
margin_top = 5.0
margin_right = 115.0
margin_bottom = 19.0
text = "Autosave interval:"
[node name="AutosaveInterval" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval"]
margin_left = 119.0
margin_right = 306.0
margin_bottom = 24.0
size_flags_horizontal = 3
min_value = 1.0
max_value = 30.0
value = 1.0
align = 2
suffix = "minute(s)"
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Languages" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 184.0
margin_right = 306.0
margin_bottom = 576.0
[node name="System Language" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_right = 306.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
pressed = true
text = "System Language"
[node name="German" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 28.0
margin_right = 306.0
margin_bottom = 52.0
mouse_default_cursor_shape = 2
text = "Deutsch [de]"
[node name="Greek" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 56.0
margin_right = 306.0
margin_bottom = 80.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 2 )
text = "Ελληνικά [el]"
[node name="English" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 84.0
margin_right = 306.0
margin_bottom = 108.0
mouse_default_cursor_shape = 2
text = "English [en]"
[node name="Esperanto" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 112.0
margin_right = 306.0
margin_bottom = 136.0
mouse_default_cursor_shape = 2
text = "Esperanto [eo]"
[node name="Spanish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 140.0
margin_right = 306.0
margin_bottom = 164.0
mouse_default_cursor_shape = 2
text = "Español [es]"
[node name="French" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 168.0
margin_right = 306.0
margin_bottom = 192.0
mouse_default_cursor_shape = 2
text = "Français [fr]"
[node name="Italian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 196.0
margin_right = 306.0
margin_bottom = 220.0
mouse_default_cursor_shape = 2
text = "Italiano [it]"
[node name="Latvian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 224.0
margin_right = 306.0
margin_bottom = 248.0
mouse_default_cursor_shape = 2
text = "Latvian [lv]"
[node name="Polish" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 252.0
margin_right = 306.0
margin_bottom = 276.0
mouse_default_cursor_shape = 2
text = "Polski [pl]"
[node name="Brazilian Portuguese" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 280.0
margin_right = 306.0
margin_bottom = 304.0
mouse_default_cursor_shape = 2
text = "Português Brasileiro [pt_BR]"
[node name="Russian" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 308.0
margin_right = 306.0
margin_bottom = 332.0
mouse_default_cursor_shape = 2
text = "Русский [ru]"
[node name="Chinese Simplified" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 336.0
margin_right = 306.0
margin_bottom = 362.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 3 )
text = "简体中文 [zh_CN]"
[node name="Chinese Traditional" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Languages"]
margin_top = 366.0
margin_right = 306.0
margin_bottom = 392.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 3 )
text = "繁體中文 [zh_TW]"
[node name="Themes" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 580.0
margin_right = 306.0
margin_bottom = 716.0
[node name="Dark Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_right = 306.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
text = "Dark"
[node name="Gray Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 28.0
margin_right = 306.0
margin_bottom = 52.0
mouse_default_cursor_shape = 2
text = "Gray"
[node name="Godot\'s Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 56.0
margin_right = 306.0
margin_bottom = 80.0
mouse_default_cursor_shape = 2
text = "Godot"
[node name="Gold Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 84.0
margin_right = 306.0
margin_bottom = 108.0
mouse_default_cursor_shape = 2
text = "Gold"
[node name="Light Theme" type="CheckBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Themes"]
margin_top = 112.0
margin_right = 306.0
margin_bottom = 136.0
mouse_default_cursor_shape = 2
text = "Light"
[node name="Canvas" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 720.0
margin_right = 306.0
margin_bottom = 912.0
[node name="GuideOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_right = 306.0
margin_bottom = 20.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="GuideColorLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions"]
margin_top = 3.0
margin_right = 110.0
margin_bottom = 17.0
rect_min_size = Vector2( 110, 0 )
hint_tooltip = "A color of ruler guides displayed on the canvas"
mouse_filter = 0
text = "Guides color:"
[node name="GuideColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions"]
margin_left = 114.0
margin_right = 306.0
margin_bottom = 20.0
rect_min_size = Vector2( 64, 20 )
hint_tooltip = "A color of ruler guides displayed on the canvas"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
color = Color( 0.63, 0.13, 0.94, 1 )
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 24.0
margin_right = 306.0
margin_bottom = 28.0
[node name="GridOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 32.0
margin_right = 306.0
margin_bottom = 108.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="WidthLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_top = 5.0
margin_right = 110.0
margin_bottom = 19.0
rect_min_size = Vector2( 110, 0 )
hint_tooltip = "Sets how far apart are vertical lines of the grid"
mouse_filter = 0
text = "Grid width:"
[node name="GridWidthValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0
margin_right = 306.0
margin_bottom = 24.0
hint_tooltip = "Sets how far apart are vertical lines of the grid"
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 1.0
align = 2
suffix = "px"
[node name="Height" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_top = 33.0
margin_right = 110.0
margin_bottom = 47.0
hint_tooltip = "Sets how far apart are horizontal lines of the grid"
mouse_filter = 0
text = "Grid height:"
[node name="GridHeightValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0
margin_top = 28.0
margin_right = 306.0
margin_bottom = 52.0
hint_tooltip = "Sets how far apart are horizontal lines of the grid"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 1.0
max_value = 16384.0
value = 1.0
align = 2
suffix = "px"
[node name="GridColorLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_top = 59.0
margin_right = 110.0
margin_bottom = 73.0
hint_tooltip = "A color of the grid"
mouse_filter = 0
text = "Grid color:"
[node name="GridColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions"]
margin_left = 114.0
margin_top = 56.0
margin_right = 306.0
margin_bottom = 76.0
rect_min_size = Vector2( 64, 20 )
hint_tooltip = "A color of the grid"
mouse_default_cursor_shape = 2
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 112.0
margin_right = 306.0
margin_bottom = 116.0
[node name="CheckerOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas"]
margin_top = 120.0
margin_right = 306.0
margin_bottom = 192.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="SizeLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_top = 5.0
margin_right = 110.0
margin_bottom = 19.0
rect_min_size = Vector2( 110, 0 )
hint_tooltip = "Size of the transparent checker background"
mouse_filter = 0
text = "Checker size:"
[node name="CheckerSizeValue" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0
margin_right = 188.0
margin_bottom = 24.0
hint_tooltip = "Size of the transparent checker background"
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 10.0
align = 2
suffix = "px"
[node name="CheckerColor1Label" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_top = 31.0
margin_right = 110.0
margin_bottom = 45.0
hint_tooltip = "First color of the transparent checker background"
mouse_filter = 0
text = "Checker color 1:"
[node name="CheckerColor1" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0
margin_top = 28.0
margin_right = 188.0
margin_bottom = 48.0
rect_min_size = Vector2( 64, 20 )
hint_tooltip = "First color of the transparent checker background"
mouse_default_cursor_shape = 2
color = Color( 0.7, 0.7, 0.7, 1 )
[node name="CheckerColor2Label" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_top = 55.0
margin_right = 110.0
margin_bottom = 69.0
hint_tooltip = "Second color of the transparent checker background"
mouse_filter = 0
text = "Checker color 2:"
[node name="CheckerColor2" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions"]
margin_left = 114.0
margin_top = 52.0
margin_right = 188.0
margin_bottom = 72.0
rect_min_size = Vector2( 64, 20 )
hint_tooltip = "Second color of the transparent checker background"
mouse_default_cursor_shape = 2
color = Color( 1, 1, 1, 1 )
[node name="Image" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 916.0
margin_right = 306.0
margin_bottom = 992.0
[node name="ImageOptions" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image"]
margin_right = 306.0
margin_bottom = 76.0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="DefaultWidthLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_top = 5.0
margin_right = 110.0
margin_bottom = 19.0
rect_min_size = Vector2( 110, 0 )
hint_tooltip = "A default width of a new image"
mouse_filter = 0
text = "Default width:"
[node name="ImageDefaultWidth" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0
margin_right = 306.0
margin_bottom = 24.0
hint_tooltip = "A default width of a new image"
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
min_value = 1.0
max_value = 16384.0
value = 64.0
align = 2
suffix = "px"
[node name="DefaultHeightLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_top = 33.0
margin_right = 110.0
margin_bottom = 47.0
hint_tooltip = "A default height of a new image"
mouse_filter = 0
text = "Default height:"
[node name="ImageDefaultHeight" type="SpinBox" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0
margin_top = 28.0
margin_right = 306.0
margin_bottom = 52.0
hint_tooltip = "A default height of a new image"
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 64.0
align = 2
suffix = "px"
[node name="DefaultFillColorLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_top = 59.0
margin_right = 110.0
margin_bottom = 73.0
hint_tooltip = "A default background color of a new image"
mouse_filter = 0
text = "Default fill color:"
[node name="DefaultFillColor" type="ColorPickerButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions"]
margin_left = 114.0
margin_top = 56.0
margin_right = 306.0
margin_bottom = 76.0
rect_min_size = Vector2( 64, 20 )
hint_tooltip = "A default background color of a new image"
mouse_default_cursor_shape = 2
color = Color( 0, 0, 0, 0 )
[node name="Shortcuts" type="VBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer"]
margin_top = 996.0
margin_right = 306.0
margin_bottom = 1230.0
[node name="HBoxContainer" type="HBoxContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_right = 306.0
margin_bottom = 20.0
hint_tooltip = "Only custom preset can be modified"
[node name="Label" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer"]
margin_top = 3.0
margin_right = 45.0
margin_bottom = 17.0
text = "Preset:"
[node name="PresetOptionButton" type="OptionButton" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer"]
margin_left = 49.0
margin_right = 306.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
text = "Default"
items = [ "Default", null, false, 0, null, "Custom", null, false, 1, null ]
selected = 0
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_top = 24.0
margin_right = 306.0
margin_bottom = 28.0
[node name="Shortcuts" type="GridContainer" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts"]
margin_top = 32.0
margin_right = 306.0
margin_bottom = 234.0
custom_constants/vseparation = 2
custom_constants/hseparation = 5
columns = 3
[node name="Empty" type="Control" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_right = 137.0
margin_bottom = 14.0
[node name="LeftToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_right = 221.0
margin_bottom = 14.0
hint_tooltip = "A tool assigned to the left mouse button"
mouse_filter = 0
text = "Left Tool:"
align = 1
[node name="RightToolLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_right = 305.0
margin_bottom = 14.0
hint_tooltip = "A tool assigned to the right mouse button"
mouse_filter = 0
text = "Right Tool:"
align = 1
[node name="Empty2" type="Control" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 16.0
margin_right = 137.0
margin_bottom = 20.0
[node name="HSeparator" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
visible = false
margin_top = 18.0
margin_right = 137.0
margin_bottom = 22.0
[node name="HSeparator2" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 16.0
margin_right = 221.0
margin_bottom = 20.0
[node name="HSeparator3" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 16.0
margin_right = 305.0
margin_bottom = 20.0
[node name="RectSelectLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 25.0
margin_right = 137.0
margin_bottom = 39.0
text = "Rectangular Selection"
[node name="left_rectangle_select_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 22.0
margin_right = 221.0
margin_bottom = 42.0
size_flags_horizontal = 3
[node name="right_rectangle_select_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 22.0
margin_right = 305.0
margin_bottom = 42.0
size_flags_horizontal = 3
[node name="ZoomLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 47.0
margin_right = 137.0
margin_bottom = 61.0
text = "Zoom"
[node name="left_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 44.0
margin_right = 221.0
margin_bottom = 64.0
size_flags_horizontal = 3
[node name="right_zoom_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 44.0
margin_right = 305.0
margin_bottom = 64.0
size_flags_horizontal = 3
[node name="ColorPickerLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 69.0
margin_right = 137.0
margin_bottom = 83.0
text = "Color Picker"
[node name="left_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 66.0
margin_right = 221.0
margin_bottom = 86.0
[node name="right_colorpicker_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 66.0
margin_right = 305.0
margin_bottom = 86.0
[node name="PencilLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 91.0
margin_right = 137.0
margin_bottom = 105.0
text = "Pencil"
[node name="left_pencil_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 88.0
margin_right = 221.0
margin_bottom = 108.0
[node name="right_pencil_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 88.0
margin_right = 305.0
margin_bottom = 108.0
[node name="EraserLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 113.0
margin_right = 137.0
margin_bottom = 127.0
text = "Eraser"
[node name="left_eraser_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 110.0
margin_right = 221.0
margin_bottom = 130.0
[node name="right_eraser_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 110.0
margin_right = 305.0
margin_bottom = 130.0
[node name="BucketLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 135.0
margin_right = 137.0
margin_bottom = 149.0
text = "Bucket"
[node name="left_fill_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 132.0
margin_right = 221.0
margin_bottom = 152.0
[node name="right_fill_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 132.0
margin_right = 305.0
margin_bottom = 152.0
[node name="LightenDarkenLabel" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 157.0
margin_right = 137.0
margin_bottom = 171.0
text = "Lighten/Darken"
[node name="left_lightdark_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 154.0
margin_right = 221.0
margin_bottom = 174.0
[node name="right_lightdark_tool" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 154.0
margin_right = 305.0
margin_bottom = 174.0
[node name="HSeparator4" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 176.0
margin_right = 137.0
margin_bottom = 180.0
[node name="HSeparator5" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 176.0
margin_right = 221.0
margin_bottom = 180.0
[node name="HSeparator6" type="HSeparator" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 226.0
margin_top = 176.0
margin_right = 305.0
margin_bottom = 180.0
[node name="Switch Colors" type="Label" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_top = 185.0
margin_right = 137.0
margin_bottom = 199.0
text = "Switch Colors"
[node name="switch_colors" type="Button" parent="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/Shortcuts"]
margin_left = 142.0
margin_top = 182.0
margin_right = 221.0
margin_bottom = 202.0
[node name="Popups" type="Node" parent="."]
[node name="ShortcutSelector" type="ConfirmationDialog" parent="Popups"]
margin_right = 250.0
margin_bottom = 87.5
rect_min_size = Vector2( 250, 87.5 )
window_title = "Set the shortcut"
dialog_text = "Press a key or a key combination to set the shortcut"
dialog_hide_on_ok = false
__meta__ = {
"_edit_use_anchors_": false
}
[node name="EnteredShortcut" type="Label" parent="Popups/ShortcutSelector"]
margin_left = 8.0
margin_top = 22.0
margin_right = 341.0
margin_bottom = 51.5
align = 1
valign = 1
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="about_to_show" from="." to="." method="_on_PreferencesDialog_about_to_show"]
[connection signal="popup_hide" from="." to="." method="_on_PreferencesDialog_popup_hide"]
[connection signal="item_selected" from="HSplitContainer/Tree" to="." method="_on_Tree_item_selected"]
[connection signal="pressed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/SmoothZoom" to="." method="_on_SmoothZoom_pressed"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftIndicatorCheckbox" to="." method="_on_LeftIndicatorCheckbox_toggled"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightIndicatorCheckbox" to="." method="_on_RightIndicatorCheckbox_toggled"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/LeftToolIconCheckbox" to="." method="_on_LeftToolIconCheckbox_toggled"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/GridContainer/RightToolIconCheckbox" to="." method="_on_RightToolIconCheckbox_toggled"]
[connection signal="item_selected" from="HSplitContainer/ScrollContainer/VBoxContainer/General/PressureSentivity/PressureSensitivityOptionButton" to="." method="_on_PressureSensitivityOptionButton_item_selected"]
[connection signal="pressed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/OpenLastProject" to="." method="_on_OpenLastProject_pressed"]
[connection signal="toggled" from="HSplitContainer/ScrollContainer/VBoxContainer/General/EnableAutosave" to="." method="_on_EnableAutosave_toggled"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/General/AutosaveInterval/AutosaveInterval" to="." method="_on_AutosaveInterval_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GuideOptions/GuideColor" to="." method="_on_GuideColor_color_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridWidthValue" to="." method="_on_GridWidthValue_value_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridHeightValue" to="." method="_on_GridHeightValue_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/GridOptions/GridColor" to="." method="_on_GridColor_color_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerSizeValue" to="." method="_on_CheckerSize_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor1" to="." method="_on_CheckerColor1_color_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Canvas/CheckerOptions/CheckerColor2" to="." method="_on_CheckerColor2_color_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultWidth" to="." method="_on_ImageDefaultWidth_value_changed"]
[connection signal="value_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/ImageDefaultHeight" to="." method="_on_ImageDefaultHeight_value_changed"]
[connection signal="color_changed" from="HSplitContainer/ScrollContainer/VBoxContainer/Image/ImageOptions/DefaultFillColor" to="." method="_on_DefaultBackground_color_changed"]
[connection signal="item_selected" from="HSplitContainer/ScrollContainer/VBoxContainer/Shortcuts/HBoxContainer/PresetOptionButton" to="." method="_on_PresetOptionButton_item_selected"]
[connection signal="confirmed" from="Popups/ShortcutSelector" to="." method="_on_ShortcutSelector_confirmed"]
[connection signal="popup_hide" from="Popups/ShortcutSelector" to="." method="_on_ShortcutSelector_popup_hide"]

View file

@ -0,0 +1,61 @@
extends ConfirmationDialog
var texture : ImageTexture
var aux_img : Image
var layer : Image
func _ready() -> void:
texture = ImageTexture.new()
texture.flags = 0
aux_img = Image.new()
$VBoxContainer/HBoxContainer2/OptionButton.add_item("Rotxel")
$VBoxContainer/HBoxContainer2/OptionButton.add_item("Upscale, Rotate and Downscale")
$VBoxContainer/HBoxContainer2/OptionButton.add_item("Nearest neighbour")
func set_sprite(sprite : Image) -> void:
aux_img.copy_from(sprite)
layer = sprite
texture.create_from_image(aux_img, 0)
$VBoxContainer/TextureRect.texture = texture
func _on_HSlider_value_changed(_value) -> void:
rotate()
$VBoxContainer/HBoxContainer/SpinBox.value = $VBoxContainer/HBoxContainer/HSlider.value
func _on_SpinBox_value_changed(_value):
$VBoxContainer/HBoxContainer/HSlider.value = $VBoxContainer/HBoxContainer/SpinBox.value
func _on_RotateImage_confirmed() -> void:
Global.canvas.handle_undo("Draw")
match $VBoxContainer/HBoxContainer2/OptionButton.text:
"Rotxel":
Global.rotxel(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Nearest neighbour":
Global.nn_rotate(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Upscale, Rotate and Downscale":
Global.fake_rotsprite(layer,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
Global.canvas.handle_redo("Draw")
$VBoxContainer/HBoxContainer/HSlider.value = 0
func rotate() -> void:
var sprite : Image = Image.new()
sprite.copy_from(aux_img)
match $VBoxContainer/HBoxContainer2/OptionButton.text:
"Rotxel":
Global.rotxel(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Nearest neighbour":
Global.nn_rotate(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
"Upscale, Rotate and Downscale":
Global.fake_rotsprite(sprite,$VBoxContainer/HBoxContainer/HSlider.value*PI/180)
texture.create_from_image(sprite, 0)
func _on_OptionButton_item_selected(_id) -> void:
rotate()
func _on_RotateImage_about_to_show() -> void:
$VBoxContainer/HBoxContainer/HSlider.value = 0

View file

@ -0,0 +1,86 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Dialogs/RotateImage.gd" type="Script" id=1]
[node name="RotateImage" type="ConfirmationDialog"]
margin_right = 245.0
margin_bottom = 241.0
resizable = true
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
margin_left = 8.0
margin_top = 8.0
margin_right = -8.0
margin_bottom = -36.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="TextureRect" type="TextureRect" parent="VBoxContainer"]
margin_right = 229.0
margin_bottom = 145.0
size_flags_vertical = 3
expand = true
stretch_mode = 6
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 149.0
margin_right = 229.0
margin_bottom = 169.0
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer2"]
margin_top = 3.0
margin_right = 34.0
margin_bottom = 17.0
text = "Type:"
[node name="OptionButton" type="OptionButton" parent="VBoxContainer/HBoxContainer2"]
margin_left = 38.0
margin_right = 229.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 173.0
margin_right = 229.0
margin_bottom = 197.0
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"]
margin_top = 5.0
margin_right = 44.0
margin_bottom = 19.0
text = "Angle: "
[node name="HSlider" type="HSlider" parent="VBoxContainer/HBoxContainer"]
margin_left = 48.0
margin_right = 151.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
size_flags_vertical = 3
max_value = 359.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="SpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"]
margin_left = 155.0
margin_right = 229.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
max_value = 359.0
[connection signal="about_to_show" from="." to="." method="_on_RotateImage_about_to_show"]
[connection signal="confirmed" from="." to="." method="_on_RotateImage_confirmed"]
[connection signal="item_selected" from="VBoxContainer/HBoxContainer2/OptionButton" to="." method="_on_OptionButton_item_selected"]
[connection signal="value_changed" from="VBoxContainer/HBoxContainer/HSlider" to="." method="_on_HSlider_value_changed"]
[connection signal="value_changed" from="VBoxContainer/HBoxContainer/SpinBox" to="." method="_on_SpinBox_value_changed"]

View file

@ -0,0 +1,21 @@
extends ConfirmationDialog
func _on_ScaleImage_confirmed() -> void:
var width : int = $VBoxContainer/OptionsContainer/WidthValue.value
var height : int = $VBoxContainer/OptionsContainer/HeightValue.value
var interpolation : int = $VBoxContainer/OptionsContainer/InterpolationType.selected
Global.undos += 1
Global.undo_redo.create_action("Scale")
Global.undo_redo.add_do_property(Global.canvas, "size", Vector2(width, height).floor())
for i in range(Global.canvas.layers.size() - 1, -1, -1):
var sprite : Image = Global.canvas.layers[i][1].get_data()
sprite.resize(width, height, interpolation)
Global.undo_redo.add_do_property(Global.canvas.layers[i][0], "data", sprite.data)
Global.undo_redo.add_undo_property(Global.canvas.layers[i][0], "data", Global.canvas.layers[i][0].data)
Global.undo_redo.add_undo_property(Global.canvas, "size", Global.canvas.size)
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
Global.undo_redo.commit_action()

View file

@ -0,0 +1,78 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Dialogs/ScaleImage.gd" type="Script" id=1]
[node name="ScaleImage" type="ConfirmationDialog"]
margin_right = 200.0
margin_bottom = 114.0
script = ExtResource( 1 )
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 8.0
margin_top = 8.0
margin_right = 192.0
margin_bottom = 102.0
[node name="ImageSize" type="Label" parent="VBoxContainer"]
margin_right = 184.0
margin_bottom = 15.0
text = "Image Size"
[node name="OptionsContainer" type="GridContainer" parent="VBoxContainer"]
margin_top = 19.0
margin_right = 184.0
margin_bottom = 90.0
custom_constants/vseparation = 4
custom_constants/hseparation = 2
columns = 2
[node name="WidthLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 5.0
margin_right = 72.0
margin_bottom = 20.0
text = "Width:"
[node name="WidthValue" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
margin_left = 72.0
margin_right = 155.0
margin_bottom = 25.0
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="Height" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 30.0
margin_right = 72.0
margin_bottom = 45.0
text = "Height:"
[node name="HeightValue" type="SpinBox" parent="VBoxContainer/OptionsContainer"]
margin_left = 72.0
margin_top = 25.0
margin_right = 155.0
margin_bottom = 50.0
mouse_default_cursor_shape = 2
min_value = 1.0
max_value = 16384.0
value = 64.0
suffix = "px"
[node name="InterpolationLabel" type="Label" parent="VBoxContainer/OptionsContainer"]
margin_top = 53.0
margin_right = 72.0
margin_bottom = 68.0
text = "Interpolation:"
[node name="InterpolationType" type="OptionButton" parent="VBoxContainer/OptionsContainer"]
margin_left = 72.0
margin_top = 50.0
margin_right = 155.0
margin_bottom = 71.0
text = "Nearest"
items = [ "Nearest", null, false, 0, null, "Bilinear", null, false, 1, null, "Cubic", null, false, 2, null, "Trilinear", null, false, 3, null, "Lanczos", null, false, 4, null ]
selected = 0
[connection signal="confirmed" from="." to="." method="_on_ScaleImage_confirmed"]

View file

@ -0,0 +1,75 @@
extends WindowDialog
onready var changes_label : Label = $"Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Changlog/ChangesLabel"
onready var art_by_label : Label = $"Contents/HBoxContainer/Logo_ArtWork/CenterContainer/ArtContainer/ArtCredits"
onready var show_on_startup_button : CheckBox = $"Contents/MarginContainer/Info/VBoxContainer/HBoxContainer/ShowOnStartup"
onready var developed_by_label : Label = $"Contents/MarginContainer/Info/VBoxContainer/Branding/VBoxContainer/DevelopedBy"
onready var platinum_placeholder_label : Label = $"Contents/MarginContainer/Info/Sponsors/PlatinumContainer/PlaceholderLabel"
onready var gold_placeholder_label : Label = $"Contents/MarginContainer/Info/Sponsors/GoldContainer/PlaceholderLabel"
func _on_SplashDialog_about_to_show() -> void:
if Global.config_cache.has_section_key("preferences", "startup"):
show_on_startup_button.pressed = !Global.config_cache.get_value("preferences", "startup")
var current_version : String = ProjectSettings.get_setting("application/config/Version")
window_title = "Pixelorama" + " " + current_version
changes_label.text = current_version + " " + tr("Changes")
art_by_label.text = tr("Art by") + ": Erevos"
if "zh" in TranslationServer.get_locale():
show_on_startup_button.add_font_override("font", preload("res://Assets/Fonts/CJK/NotoSansCJKtc-Small.tres"))
developed_by_label.add_font_override("font", preload("res://Assets/Fonts/CJK/NotoSansCJKtc-Small.tres"))
platinum_placeholder_label.add_font_override("font", preload("res://Assets/Fonts/CJK/NotoSansCJKtc-Bold.tres"))
gold_placeholder_label.add_font_override("font", preload("res://Assets/Fonts/CJK/NotoSansCJKtc-Bold.tres"))
else:
show_on_startup_button.add_font_override("font", preload("res://Assets/Fonts/Roboto-Small.tres"))
developed_by_label.add_font_override("font", preload("res://Assets/Fonts/Roboto-Small.tres"))
platinum_placeholder_label.add_font_override("font", preload("res://Assets/Fonts/Roboto-Bold.tres"))
gold_placeholder_label.add_font_override("font", preload("res://Assets/Fonts/Roboto-Bold.tres"))
func _on_ArtCredits_pressed() -> void:
OS.shell_open("https://www.instagram.com/erevoid")
func _on_ShowOnStartup_toggled(pressed : bool) -> void:
if pressed:
Global.config_cache.set_value("preferences", "startup", false)
else:
Global.config_cache.set_value("preferences", "startup", true)
func _on_PatronButton_pressed() -> void:
OS.shell_open("https://www.patreon.com/OramaInteractive")
func _on_TakeThisSpot_pressed() -> void:
OS.shell_open("https://www.patreon.com/OramaInteractive")
func _on_GithubButton_pressed() -> void:
OS.shell_open("https://github.com/Orama-Interactive/Pixelorama")
func _on_DiscordButton_pressed() -> void:
OS.shell_open("https://discord.gg/GTMtr8s")
func _on_NewBtn_pressed() -> void:
Global.control.file_menu_id_pressed(0)
visible = false
func _on_OpenBtn__pressed() -> void:
Global.control.file_menu_id_pressed(1)
visible = false
func _on_OpenLastBtn_pressed() -> void:
Global.control.file_menu_id_pressed(2)
visible = false
func _on_ImportBtn_pressed() -> void:
Global.control.file_menu_id_pressed(5)
visible = false

View file

@ -0,0 +1,441 @@
[gd_scene load_steps=12 format=2]
[ext_resource path="res://src/UI/Dialogs/SplashDialog.gd" type="Script" id=1]
[ext_resource path="res://Assets/Graphics/Pixelorama Logo.png" type="Texture" id=2]
[ext_resource path="res://Assets/Graphics/Become a patron.png" type="Texture" id=3]
[ext_resource path="res://Assets/Graphics/Become a patron_Hover.png" type="Texture" id=4]
[ext_resource path="res://Assets/Graphics/Splash Art.png" type="Texture" id=5]
[ext_resource path="res://Assets/Fonts/Roboto-Bold.tres" type="DynamicFont" id=6]
[ext_resource path="res://Assets/Fonts/Roboto-Small.tres" type="DynamicFont" id=7]
[ext_resource path="res://Assets/Graphics/orama_64x64.png" type="Texture" id=8]
[ext_resource path="res://Assets/Graphics/discord.png" type="Texture" id=9]
[ext_resource path="res://Assets/Graphics/GitHub-32px.png" type="Texture" id=10]
[ext_resource path="res://Assets/Graphics/Patreon_Mark_White.png" type="Texture" id=11]
[node name="SplashDialog" type="WindowDialog"]
margin_right = 614.0
margin_bottom = 590.0
rect_min_size = Vector2( 600, 560 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Contents" type="VBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
custom_constants/separation = 0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="HBoxContainer" type="HBoxContainer" parent="Contents"]
margin_right = 617.0
margin_bottom = 436.0
custom_constants/separation = 0
[node name="Logo_ArtWork" type="VBoxContainer" parent="Contents/HBoxContainer"]
margin_right = 350.0
margin_bottom = 436.0
rect_min_size = Vector2( 350, 0 )
custom_constants/separation = 15
[node name="PixeloramaLogo" type="TextureRect" parent="Contents/HBoxContainer/Logo_ArtWork"]
margin_right = 350.0
margin_bottom = 124.0
rect_min_size = Vector2( 0, 80 )
size_flags_horizontal = 3
size_flags_vertical = 3
texture = ExtResource( 2 )
stretch_mode = 6
[node name="CenterContainer" type="MarginContainer" parent="Contents/HBoxContainer/Logo_ArtWork"]
margin_top = 139.0
margin_right = 350.0
margin_bottom = 436.0
size_flags_horizontal = 3
size_flags_vertical = 0
[node name="ArtContainer" type="VBoxContainer" parent="Contents/HBoxContainer/Logo_ArtWork/CenterContainer"]
margin_right = 350.0
margin_bottom = 297.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/separation = 17
[node name="SplashArt" type="TextureButton" parent="Contents/HBoxContainer/Logo_ArtWork/CenterContainer/ArtContainer"]
margin_left = 45.0
margin_right = 305.0
margin_bottom = 260.0
rect_min_size = Vector2( 260, 260 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 6
texture_normal = ExtResource( 5 )
expand = true
stretch_mode = 5
[node name="ArtCredits" type="Button" parent="Contents/HBoxContainer/Logo_ArtWork/CenterContainer/ArtContainer"]
margin_top = 277.0
margin_right = 350.0
margin_bottom = 297.0
mouse_default_cursor_shape = 2
custom_constants/hseparation = 0
text = "Art by Erevoid"
flat = true
[node name="VSeparator" type="VSeparator" parent="Contents/HBoxContainer"]
margin_left = 350.0
margin_right = 354.0
margin_bottom = 436.0
[node name="Buttons_Changelog" type="MarginContainer" parent="Contents/HBoxContainer"]
margin_left = 354.0
margin_right = 617.0
margin_bottom = 436.0
size_flags_horizontal = 3
custom_constants/margin_right = 10
custom_constants/margin_top = 10
custom_constants/margin_left = 10
custom_constants/margin_bottom = 10
[node name="VBoxContainer" type="VBoxContainer" parent="Contents/HBoxContainer/Buttons_Changelog"]
margin_left = 10.0
margin_top = 10.0
margin_right = 253.0
margin_bottom = 426.0
size_flags_horizontal = 3
custom_constants/separation = 10
[node name="Buttons" type="VBoxContainer" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer"]
margin_right = 243.0
margin_bottom = 110.0
size_flags_vertical = 3
custom_constants/separation = 10
[node name="NewBtn" type="Button" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons"]
margin_right = 243.0
margin_bottom = 20.0
text = "New"
[node name="OpenBtn " type="Button" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons"]
margin_top = 30.0
margin_right = 243.0
margin_bottom = 50.0
text = "Open"
[node name="OpenLastBtn" type="Button" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons"]
margin_top = 60.0
margin_right = 243.0
margin_bottom = 80.0
text = "Open Last Project"
[node name="ImportBtn" type="Button" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons"]
margin_top = 90.0
margin_right = 243.0
margin_bottom = 110.0
text = "Import"
[node name="HSeparator" type="HSeparator" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer"]
margin_top = 120.0
margin_right = 243.0
margin_bottom = 124.0
[node name="Changlog" type="VBoxContainer" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer"]
margin_top = 134.0
margin_right = 243.0
margin_bottom = 416.0
size_flags_vertical = 3
custom_constants/separation = 8
[node name="ChangesLabel" type="Label" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Changlog"]
margin_right = 243.0
margin_bottom = 14.0
size_flags_horizontal = 3
size_flags_vertical = 8
text = "v0.6 Changes"
[node name="ChangelogContainer" type="VBoxContainer" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Changlog"]
margin_top = 22.0
margin_right = 243.0
margin_bottom = 282.0
size_flags_horizontal = 3
[node name="ChangelogScroll" type="ScrollContainer" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Changlog/ChangelogContainer"]
margin_right = 243.0
margin_bottom = 260.0
rect_min_size = Vector2( 0, 260 )
[node name="Label" type="Label" parent="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Changlog/ChangelogContainer/ChangelogScroll"]
margin_right = 243.0
margin_bottom = 1680.0
size_flags_horizontal = 3
size_flags_vertical = 3
text = "Added
- Image layer rotation! Choose between 2 rotation algorithms, Rotxel and Nearest Neighbour - Thanks to azagaya!
- Crowdin integration for contributing translations!
- Spanish translation - thanks to azagaya & Lilly And!
- Chinese Simplified translation - thanks to Chenxu Wang!
- Latvian translation - thanks to Agnis Aldiņš (NeZvers)!
- Translators can now be seen in the About window.
- It is now possible to remove custom brushes with the middle mouse button.
- Added HSV mode to the color picker. (Added automatically because of the Godot 3.2 update)
- Lanczos scaling interpolation. (Added because of the Godot 3.2 update)
- You can now drag and drop (or right click and open with) image and .pxo files in Pixelorama.
- You can now hide the animation timeline - Thanks to YeldhamDev!
Changed
- Major changes to alpha blending behavior. The alpha values now get added/blended together instead of just replacing the pixel with the new value.
- Replaced some OS alerts with a custom made error dialog.
- Made the zooming smoother, is toggleable in Preferences whether to keep the new zooming or the old one.
- The camera now zooms at the mouse's position.
- Made the \"X\" button on the custom brushes a little smaller.
- The color picker will now have a small white triangle on the top left of the color preview if at least one of its RGB values are above 1 in Raw mode. (Added automatically because of the Godot 3.2 update)
- You can now toggle the visibility of hidden items on and off in the file dialogs. (Added automatically because of the Godot 3.2 update)
- The language buttons in the preferences have their localized names in their hint tooltips. For example, if you hover over the \"English\" button while the language is Greek, the hint tooltip will be \"Αγγλικά\", which is the Greek word for English.
- Translation updates.
- The presets in the ColorPickers are now hidden - Thanks to YeldhamDev!
- When opening a project (.pxo file), the save path is being set to the opened project's path - Thanks to YeldhamDev!
Fixed
- Delay the splash screen popup so it shows properly centered - Thanks to YeldhamDev!
- Possibly fixed crashes with motion drawing and undo/redoing.
- Fixed bug (which also caused crashes sometimes) when generating an outline inside the image and it was going outside the canvas' borders.
- Fixed crash when importing images that were failing to load. They still fail to load, but Pixelorama does not crash.
- Possibly fixed a rare crash where the cursor image was failing to load. It is now being loaded only once.
- Fixed ruler markings cutting off before they should - Thanks to YeldhamDev!
- Fixed bug where resizing the image on export was not working on Godot 3.2 - Issue #161"
autowrap = true
[node name="HSeparator" type="HSeparator" parent="Contents"]
margin_top = 436.0
margin_right = 617.0
margin_bottom = 440.0
[node name="MarginContainer" type="MarginContainer" parent="Contents"]
margin_top = 440.0
margin_right = 617.0
margin_bottom = 593.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/margin_right = 10
custom_constants/margin_top = 10
custom_constants/margin_left = 10
custom_constants/margin_bottom = 10
[node name="Info" type="HBoxContainer" parent="Contents/MarginContainer"]
margin_left = 10.0
margin_top = 10.0
margin_right = 607.0
margin_bottom = 143.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/separation = 3
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Sponsors" type="HBoxContainer" parent="Contents/MarginContainer/Info"]
margin_right = 362.0
margin_bottom = 133.0
size_flags_vertical = 3
custom_constants/separation = 5
[node name="PlatinumContainer" type="VBoxContainer" parent="Contents/MarginContainer/Info/Sponsors"]
margin_right = 125.0
margin_bottom = 133.0
rect_min_size = Vector2( 125, 0 )
[node name="Label" type="Label" parent="Contents/MarginContainer/Info/Sponsors/PlatinumContainer"]
margin_right = 125.0
margin_bottom = 14.0
text = "Platinum Sponsor"
align = 1
[node name="PlaceholderLabel" type="Label" parent="Contents/MarginContainer/Info/Sponsors/PlatinumContainer"]
margin_top = 47.0
margin_right = 125.0
margin_bottom = 80.0
size_flags_vertical = 6
custom_fonts/font = ExtResource( 6 )
custom_colors/font_color = Color( 0.678431, 0.611765, 0.807843, 1 )
text = "Platinum
Sponsor"
align = 1
[node name="TakeThisSpot" type="Button" parent="Contents/MarginContainer/Info/Sponsors/PlatinumContainer"]
margin_top = 113.0
margin_right = 125.0
margin_bottom = 133.0
mouse_default_cursor_shape = 2
text = "Take this spot!"
flat = true
[node name="VSeparator" type="VSeparator" parent="Contents/MarginContainer/Info/Sponsors"]
margin_left = 130.0
margin_right = 134.0
margin_bottom = 133.0
[node name="GoldContainer" type="VBoxContainer" parent="Contents/MarginContainer/Info/Sponsors"]
margin_left = 139.0
margin_right = 264.0
margin_bottom = 133.0
rect_min_size = Vector2( 125, 0 )
size_flags_horizontal = 3
[node name="Label" type="Label" parent="Contents/MarginContainer/Info/Sponsors/GoldContainer"]
margin_right = 125.0
margin_bottom = 14.0
text = "Gold Sponsors"
align = 1
[node name="PlaceholderLabel" type="Label" parent="Contents/MarginContainer/Info/Sponsors/GoldContainer"]
margin_top = 47.0
margin_right = 125.0
margin_bottom = 80.0
size_flags_vertical = 6
custom_fonts/font = ExtResource( 6 )
custom_colors/font_color = Color( 0.678431, 0.611765, 0.807843, 1 )
text = "Gold
Sponsors"
align = 1
[node name="TakeThisSpot" type="Button" parent="Contents/MarginContainer/Info/Sponsors/GoldContainer"]
margin_top = 113.0
margin_right = 125.0
margin_bottom = 133.0
mouse_default_cursor_shape = 2
text = "Take this spot!"
flat = true
[node name="VSeparator2" type="VSeparator" parent="Contents/MarginContainer/Info/Sponsors"]
margin_left = 269.0
margin_right = 273.0
margin_bottom = 133.0
[node name="PatronContainer" type="VBoxContainer" parent="Contents/MarginContainer/Info/Sponsors"]
margin_left = 278.0
margin_right = 362.0
margin_bottom = 133.0
size_flags_horizontal = 3
custom_constants/separation = 10
alignment = 1
[node name="PatronsLabel" type="Label" parent="Contents/MarginContainer/Info/Sponsors/PatronContainer"]
margin_right = 84.0
margin_bottom = 14.0
size_flags_horizontal = 3
size_flags_vertical = 8
text = "Patrons:"
align = 1
[node name="PatronButton" type="TextureButton" parent="Contents/MarginContainer/Info/Sponsors/PatronContainer"]
margin_top = 24.0
margin_right = 84.0
margin_bottom = 133.0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
size_flags_vertical = 3
texture_normal = ExtResource( 3 )
texture_hover = ExtResource( 4 )
stretch_mode = 5
[node name="VBoxContainer" type="VBoxContainer" parent="Contents/MarginContainer/Info"]
margin_left = 365.0
margin_right = 597.0
margin_bottom = 133.0
size_flags_horizontal = 3
size_flags_vertical = 3
custom_constants/separation = 5
alignment = 2
[node name="Branding" type="HBoxContainer" parent="Contents/MarginContainer/Info/VBoxContainer"]
margin_right = 232.0
margin_bottom = 104.0
size_flags_horizontal = 3
size_flags_vertical = 3
alignment = 2
[node name="VBoxContainer" type="VBoxContainer" parent="Contents/MarginContainer/Info/VBoxContainer/Branding"]
margin_left = 99.0
margin_right = 196.0
margin_bottom = 104.0
size_flags_vertical = 3
alignment = 1
[node name="Logo" type="TextureRect" parent="Contents/MarginContainer/Info/VBoxContainer/Branding/VBoxContainer"]
margin_top = 3.0
margin_right = 97.0
margin_bottom = 67.0
texture = ExtResource( 8 )
stretch_mode = 4
[node name="DevelopedBy" type="Label" parent="Contents/MarginContainer/Info/VBoxContainer/Branding/VBoxContainer"]
margin_top = 71.0
margin_right = 97.0
margin_bottom = 84.0
custom_fonts/font = ExtResource( 7 )
text = "Orama Interactive"
align = 1
[node name="Copyright" type="Label" parent="Contents/MarginContainer/Info/VBoxContainer/Branding/VBoxContainer"]
margin_top = 88.0
margin_right = 97.0
margin_bottom = 101.0
custom_fonts/font = ExtResource( 7 )
text = "Copyright 2019-2020"
align = 1
[node name="Links" type="VBoxContainer" parent="Contents/MarginContainer/Info/VBoxContainer/Branding"]
margin_left = 200.0
margin_right = 232.0
margin_bottom = 104.0
[node name="TextureButton" type="TextureButton" parent="Contents/MarginContainer/Info/VBoxContainer/Branding/Links"]
margin_right = 32.0
margin_bottom = 32.0
texture_normal = ExtResource( 10 )
[node name="TextureButton2" type="TextureButton" parent="Contents/MarginContainer/Info/VBoxContainer/Branding/Links"]
margin_top = 36.0
margin_right = 32.0
margin_bottom = 68.0
texture_normal = ExtResource( 9 )
[node name="TextureButton3" type="TextureButton" parent="Contents/MarginContainer/Info/VBoxContainer/Branding/Links"]
margin_top = 72.0
margin_right = 32.0
margin_bottom = 104.0
texture_normal = ExtResource( 11 )
[node name="HBoxContainer" type="HBoxContainer" parent="Contents/MarginContainer/Info/VBoxContainer"]
margin_top = 109.0
margin_right = 232.0
margin_bottom = 133.0
alignment = 2
[node name="ShowOnStartup" type="CheckBox" parent="Contents/MarginContainer/Info/VBoxContainer/HBoxContainer"]
margin_left = 127.0
margin_right = 232.0
margin_bottom = 24.0
mouse_default_cursor_shape = 2
custom_fonts/font = ExtResource( 7 )
text = "Don't show again"
[connection signal="about_to_show" from="." to="." method="_on_SplashDialog_about_to_show"]
[connection signal="pressed" from="Contents/HBoxContainer/Logo_ArtWork/CenterContainer/ArtContainer/SplashArt" to="." method="_on_ArtCredits_pressed"]
[connection signal="pressed" from="Contents/HBoxContainer/Logo_ArtWork/CenterContainer/ArtContainer/ArtCredits" to="." method="_on_ArtCredits_pressed"]
[connection signal="pressed" from="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons/NewBtn" to="." method="_on_NewBtn_pressed"]
[connection signal="pressed" from="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons/OpenBtn " to="." method="_on_OpenBtn__pressed"]
[connection signal="pressed" from="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons/OpenLastBtn" to="." method="_on_OpenLastBtn_pressed"]
[connection signal="pressed" from="Contents/HBoxContainer/Buttons_Changelog/VBoxContainer/Buttons/ImportBtn" to="." method="_on_ImportBtn_pressed"]
[connection signal="pressed" from="Contents/MarginContainer/Info/Sponsors/PlatinumContainer/TakeThisSpot" to="." method="_on_TakeThisSpot_pressed"]
[connection signal="pressed" from="Contents/MarginContainer/Info/Sponsors/GoldContainer/TakeThisSpot" to="." method="_on_TakeThisSpot_pressed"]
[connection signal="pressed" from="Contents/MarginContainer/Info/Sponsors/PatronContainer/PatronButton" to="." method="_on_PatronButton_pressed"]
[connection signal="pressed" from="Contents/MarginContainer/Info/VBoxContainer/Branding/Links/TextureButton" to="." method="_on_GithubButton_pressed"]
[connection signal="pressed" from="Contents/MarginContainer/Info/VBoxContainer/Branding/Links/TextureButton2" to="." method="_on_DiscordButton_pressed"]
[connection signal="pressed" from="Contents/MarginContainer/Info/VBoxContainer/Branding/Links/TextureButton3" to="." method="_on_PatronButton_pressed"]
[connection signal="toggled" from="Contents/MarginContainer/Info/VBoxContainer/HBoxContainer/ShowOnStartup" to="." method="_on_ShowOnStartup_toggled"]

View file

@ -0,0 +1,12 @@
extends Label
func _ready() -> void:
var tween := $Tween
tween.interpolate_property(self, "rect_position", rect_position, Vector2(rect_position.x, rect_position.y - 100), 1, Tween.TRANS_LINEAR, Tween.EASE_OUT)
tween.interpolate_property(self, "modulate", modulate, Color(modulate.r, modulate.g, modulate.b, 0), 1, Tween.TRANS_LINEAR, Tween.EASE_OUT)
tween.start()
func _on_Timer_timeout() -> void:
queue_free()

View file

@ -0,0 +1,22 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/NotificationLabel.gd" type="Script" id=2]
[node name="NotificationLabel" type="Label"]
margin_right = 116.0
margin_bottom = 14.0
custom_colors/font_color_shadow = Color( 0, 0, 0, 1 )
text = "Undo: Notification"
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Tween" type="Tween" parent="."]
[node name="Timer" type="Timer" parent="."]
one_shot = true
autostart = true
[connection signal="timeout" from="Timer" to="." method="_on_Timer_timeout"]

29
src/UI/PatternButton.gd Normal file
View file

@ -0,0 +1,29 @@
extends TextureButton
var image : Image
var image_size : Vector2
var texture : ImageTexture
func _ready() -> void:
if image:
image_size = image.get_size()
texture = ImageTexture.new()
texture.create_from_image(image, 0)
func _on_PatternButton_pressed() -> void:
if Global.pattern_window_position == "left":
Global.pattern_left_image = image
Global.left_fill_pattern_container.get_child(0).get_child(0).texture = texture
Global.left_fill_pattern_container.get_child(2).get_child(1).max_value = image_size.x - 1
Global.left_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1
elif Global.pattern_window_position == "right":
Global.pattern_right_image = image
Global.right_fill_pattern_container.get_child(0).get_child(0).texture = texture
Global.right_fill_pattern_container.get_child(2).get_child(1).max_value = image_size.x - 1
Global.right_fill_pattern_container.get_child(3).get_child(1).max_value = image_size.y - 1
Global.patterns_popup.hide()

29
src/UI/PatternButton.tscn Normal file
View file

@ -0,0 +1,29 @@
[gd_scene load_steps=3 format=2]
[ext_resource path="res://Assets/Graphics/Brush_button.png" type="Texture" id=1]
[ext_resource path="res://src/UI/PatternButton.gd" type="Script" id=2]
[node name="PatternButton" type="TextureButton"]
margin_right = 32.0
margin_bottom = 32.0
rect_min_size = Vector2( 3, 0 )
button_mask = 7
texture_normal = ExtResource( 1 )
stretch_mode = 5
script = ExtResource( 2 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PatternTexture" type="TextureRect" parent="."]
margin_right = 32.0
margin_bottom = 32.0
rect_min_size = Vector2( 32, 32 )
expand = true
stretch_mode = 6
__meta__ = {
"_edit_use_anchors_": false
}
[connection signal="pressed" from="." to="." method="_on_PatternButton_pressed"]

76
src/UI/Rulers/Guides.gd Normal file
View file

@ -0,0 +1,76 @@
class_name Guide
extends Line2D
enum Types {HORIZONTAL, VERTICAL}
var font := preload("res://Assets/Fonts/Roboto-Regular.tres")
var has_focus := true
var mouse_pos := Vector2.ZERO
var previous_points := points
var type = Types.HORIZONTAL
func _ready() -> void:
width = 0.1
default_color = Global.guide_color
func _input(_event : InputEvent):
width = Global.camera.zoom.x * 2
mouse_pos = get_local_mouse_position()
var point0 := points[0]
var point1 := points[1]
if type == Types.HORIZONTAL:
point0.y -= width * 3
point1.y += width * 3
else:
point0.x -= width * 3
point1.x += width * 3
if Global.can_draw and Global.has_focus and point_in_rectangle(mouse_pos, point0, point1) and Input.is_action_just_pressed("left_mouse"):
if !point_in_rectangle(Global.canvas.current_pixel, Global.canvas.location, Global.canvas.location + Global.canvas.size):
has_focus = true
Global.has_focus = false
update()
if has_focus:
if Input.is_action_just_pressed("left_mouse"):
previous_points = points
if Input.is_action_pressed("left_mouse"):
if type == Types.HORIZONTAL:
points[0].y = round(mouse_pos.y)
points[1].y = round(mouse_pos.y)
else:
points[0].x = round(mouse_pos.x)
points[1].x = round(mouse_pos.x)
if Input.is_action_just_released("left_mouse"):
Global.has_focus = true
has_focus = false
if !outside_canvas():
update()
func _draw() -> void:
if has_focus:
var viewport_size: Vector2 = Global.main_viewport.rect_size
var zoom: Vector2 = Global.camera.zoom
if type == Types.HORIZONTAL:
draw_set_transform(Vector2(Global.camera.offset.x - (viewport_size.x / 2) * zoom.x, points[0].y + font.get_height() * zoom.x * 2), rotation, zoom * 2)
draw_string(font, Vector2.ZERO, "%spx" % str(round(mouse_pos.y)))
else:
draw_set_transform(Vector2(points[0].x + font.get_height() * zoom.y, Global.camera.offset.y - (viewport_size.y / 2.25) * zoom.y), rotation, zoom * 2)
draw_string(font, Vector2.ZERO, "%spx" % str(round(mouse_pos.x)))
func outside_canvas() -> bool:
if type == Types.HORIZONTAL:
if points[0].y < 0 || points[0].y > Global.canvas.size.y:
queue_free()
return true
else:
if points[0].x < 0 || points[0].x > Global.canvas.size.x:
queue_free()
return true
return false
func point_in_rectangle(p : Vector2, coord1 : Vector2, coord2 : Vector2) -> bool:
return p.x > coord1.x && p.y > coord1.y && p.x < coord2.x && p.y < coord2.y

View file

@ -0,0 +1,79 @@
extends Button
const RULER_WIDTH := 16
var font := preload("res://Assets/Fonts/Roboto-Small.tres")
var major_subdivision := 2
var minor_subdivision := 4
var first : Vector2
var last : Vector2
func _ready() -> void:
Global.main_viewport.connect("item_rect_changed", self, "update")
# Code taken and modified from Godot's source code
func _draw() -> void:
var transform := Transform2D()
var ruler_transform := Transform2D()
var major_subdivide := Transform2D()
var minor_subdivide := Transform2D()
var zoom: float = 1 / Global.camera.zoom.x
transform.x = Vector2(zoom, zoom)
transform.origin = Global.main_viewport.rect_size / 2 + Global.camera.offset * -zoom
var basic_rule := 100.0
var i := 0
while(basic_rule * zoom > 100):
basic_rule /= 5.0 if i % 2 else 2.0
i += 1
i = 0
while(basic_rule * zoom < 100):
basic_rule *= 2.0 if i % 2 else 5.0
i += 1
ruler_transform = ruler_transform.scaled(Vector2(basic_rule, basic_rule))
major_subdivide = major_subdivide.scaled(Vector2(1.0 / major_subdivision, 1.0 / major_subdivision))
minor_subdivide = minor_subdivide.scaled(Vector2(1.0 / minor_subdivision, 1.0 / minor_subdivision))
first = (transform * ruler_transform * major_subdivide * minor_subdivide).affine_inverse().xform(Vector2.ZERO)
last = (transform * ruler_transform * major_subdivide * minor_subdivide).affine_inverse().xform(Global.main_viewport.rect_size)
for i in range(ceil(first.x), ceil(last.x)):
var position : Vector2 = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Vector2(i, 0))
if i % (major_subdivision * minor_subdivision) == 0:
draw_line(Vector2(position.x + RULER_WIDTH, 0), Vector2(position.x + RULER_WIDTH, RULER_WIDTH), Color.white)
var val = (ruler_transform * major_subdivide * minor_subdivide).xform(Vector2(i, 0)).x
draw_string(font, Vector2(position.x + RULER_WIDTH + 2, font.get_height() - 4), str(int(val)))
else:
if i % minor_subdivision == 0:
draw_line(Vector2(position.x + RULER_WIDTH, RULER_WIDTH * 0.33), Vector2(position.x + RULER_WIDTH, RULER_WIDTH), Color.white)
else:
draw_line(Vector2(position.x + RULER_WIDTH, RULER_WIDTH * 0.66), Vector2(position.x + RULER_WIDTH, RULER_WIDTH), Color.white)
func _on_HorizontalRuler_pressed() -> void:
if !Global.show_guides:
return
var mouse_pos := get_local_mouse_position()
if mouse_pos.x < RULER_WIDTH: # For double guides
Global.vertical_ruler._on_VerticalRuler_pressed()
var guide := Guide.new()
guide.type = guide.Types.HORIZONTAL
guide.add_point(Vector2(-99999, Global.canvas.current_pixel.y))
guide.add_point(Vector2(99999, Global.canvas.current_pixel.y))
Global.canvas.add_child(guide)
Global.has_focus = false
update()
func _on_HorizontalRuler_mouse_entered() -> void:
var mouse_pos := get_local_mouse_position()
if mouse_pos.x < RULER_WIDTH: # For double guides
mouse_default_cursor_shape = Control.CURSOR_FDIAGSIZE
else:
mouse_default_cursor_shape = Control.CURSOR_VSPLIT

View file

@ -0,0 +1,71 @@
extends Button
const RULER_WIDTH := 16
var font := preload("res://Assets/Fonts/Roboto-Small.tres")
var major_subdivision := 2
var minor_subdivision := 4
var first : Vector2
var last : Vector2
func _ready() -> void:
Global.main_viewport.connect("item_rect_changed", self, "update")
# Code taken and modified from Godot's source code
func _draw() -> void:
var transform := Transform2D()
var ruler_transform := Transform2D()
var major_subdivide := Transform2D()
var minor_subdivide := Transform2D()
var zoom: float = 1 / Global.camera.zoom.x
transform.y = Vector2(zoom, zoom)
transform.origin = Global.main_viewport.rect_size / 2 + Global.camera.offset * -zoom
var basic_rule := 100.0
var i := 0
while(basic_rule * zoom > 100):
basic_rule /= 5.0 if i % 2 else 2.0
i += 1
i = 0
while(basic_rule * zoom < 100):
basic_rule *= 2.0 if i % 2 else 5.0
i += 1
ruler_transform = ruler_transform.scaled(Vector2(basic_rule, basic_rule))
major_subdivide = major_subdivide.scaled(Vector2(1.0 / major_subdivision, 1.0 / major_subdivision))
minor_subdivide = minor_subdivide.scaled(Vector2(1.0 / minor_subdivision, 1.0 / minor_subdivision))
first = (transform * ruler_transform * major_subdivide * minor_subdivide).affine_inverse().xform(Vector2.ZERO)
last = (transform * ruler_transform * major_subdivide * minor_subdivide).affine_inverse().xform(Global.main_viewport.rect_size)
for i in range(ceil(first.y), ceil(last.y)):
var position : Vector2 = (transform * ruler_transform * major_subdivide * minor_subdivide).xform(Vector2(0, i))
if i % (major_subdivision * minor_subdivision) == 0:
draw_line(Vector2(0, position.y), Vector2(RULER_WIDTH, position.y), Color.white)
var text_xform = Transform2D(-PI / 2, Vector2(font.get_height() - 4, position.y - 2))
draw_set_transform_matrix(get_transform() * text_xform)
var val = (ruler_transform * major_subdivide * minor_subdivide).xform(Vector2(0, i)).y
draw_string(font, Vector2(), str(int(val)))
draw_set_transform_matrix(get_transform())
else:
if i % minor_subdivision == 0:
draw_line(Vector2(RULER_WIDTH * 0.33, position.y), Vector2(RULER_WIDTH, position.y), Color.white)
else:
draw_line(Vector2(RULER_WIDTH * 0.66, position.y), Vector2(RULER_WIDTH, position.y), Color.white)
func _on_VerticalRuler_pressed() -> void:
if !Global.show_guides:
return
var guide := Guide.new()
guide.type = guide.Types.VERTICAL
guide.add_point(Vector2(Global.canvas.current_pixel.x, -99999))
guide.add_point(Vector2(Global.canvas.current_pixel.x, 99999))
Global.canvas.add_child(guide)
Global.has_focus = false
update()

6
src/UI/SecondViewport.gd Normal file
View file

@ -0,0 +1,6 @@
extends Viewport
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
world_2d = Global.canvas.get_parent().world_2d

View file

@ -0,0 +1,24 @@
[gd_scene format=2]
[node name="AnimationTag" type="VBoxContainer"]
margin_right = 39.0
margin_bottom = 32.0
rect_min_size = Vector2( 39, 32 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Line2D" type="Line2D" parent="."]
points = PoolVector2Array( 0, 32, 0, 0, 39, 0, 39, 32 )
width = 1.0
texture_mode = 1313163520
[node name="Label" type="Label" parent="."]
margin_left = 7.0
margin_right = 32.0
margin_bottom = 32.0
size_flags_horizontal = 4
size_flags_vertical = 3
text = "Idle"
align = 1
valign = 1

View file

@ -0,0 +1,494 @@
extends Panel
var fps := 6.0
var animation_loop := 1 # 0 is no loop, 1 is cycle loop, 2 is ping-pong loop
var animation_forward := true
var first_frame := 0
var last_frame := Global.canvases.size() - 1
onready var timeline_scroll : ScrollContainer = $AnimationContainer/TimelineContainer/TimelineScroll
onready var tag_scroll_container : ScrollContainer = $AnimationContainer/TimelineContainer/OpacityAndTagContainer/TagScroll
func _ready() -> void:
timeline_scroll.get_h_scrollbar().connect("value_changed", self, "_h_scroll_changed")
Global.animation_timer.wait_time = 1 / fps
func _h_scroll_changed(value : float) -> void:
# Let the main timeline ScrollContainer affect the tag ScrollContainer too
tag_scroll_container.get_child(0).rect_min_size.x = timeline_scroll.get_child(0).rect_size.x - 212
tag_scroll_container.scroll_horizontal = value
func add_frame() -> void:
var new_canvas : Canvas = load("res://src/Canvas.tscn").instance()
new_canvas.size = Global.canvas.size
new_canvas.frame = Global.canvases.size()
var new_canvases: Array = Global.canvases.duplicate()
new_canvases.append(new_canvas)
Global.undos += 1
Global.undo_redo.create_action("Add Frame")
Global.undo_redo.add_do_method(Global, "redo", [new_canvas])
Global.undo_redo.add_undo_method(Global, "undo", [new_canvas])
Global.undo_redo.add_do_property(Global, "canvases", new_canvases)
Global.undo_redo.add_do_property(Global, "canvas", new_canvas)
Global.undo_redo.add_do_property(Global, "current_frame", new_canvases.size() - 1)
for c in Global.canvases:
Global.undo_redo.add_do_property(c, "visible", false)
Global.undo_redo.add_undo_property(c, "visible", c.visible)
for l_i in range(Global.layers.size()):
if Global.layers[l_i][4]: # If the link button is pressed
Global.layers[l_i][5].append(new_canvas)
Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases)
Global.undo_redo.add_undo_property(Global, "canvas", Global.canvas)
Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame)
Global.undo_redo.commit_action()
func _on_DeleteFrame_pressed(frame := -1) -> void:
if Global.canvases.size() == 1:
return
if frame == -1:
frame = Global.current_frame
var canvas : Canvas = Global.canvases[frame]
var new_canvases := Global.canvases.duplicate()
new_canvases.erase(canvas)
var current_frame := Global.current_frame
if current_frame > 0 && current_frame == new_canvases.size(): # If it's the last frame
current_frame -= 1
var new_animation_tags := Global.animation_tags.duplicate(true)
# Loop through the tags to see if the frame is in one
for tag in new_animation_tags:
if frame + 1 >= tag[2] && frame + 1 <= tag[3]:
if tag[3] == tag[2]: # If we're deleting the only frame in the tag
new_animation_tags.erase(tag)
else:
tag[3] -= 1
elif frame + 1 < tag[2]:
tag[2] -= 1
tag[3] -= 1
# Check if one of the cels of the frame is linked
# if they are, unlink them too
# this prevents removed cels being kept in linked memory
var new_layers := Global.layers.duplicate(true)
for layer in new_layers:
for linked in layer[5]:
if linked == Global.canvases[frame]:
layer[5].erase(linked)
Global.undos += 1
Global.undo_redo.create_action("Remove Frame")
Global.undo_redo.add_do_property(Global, "canvases", new_canvases)
Global.undo_redo.add_do_property(Global, "canvas", new_canvases[current_frame])
Global.undo_redo.add_do_property(Global, "current_frame", current_frame)
Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags)
Global.undo_redo.add_do_property(Global, "layers", new_layers)
# Change the frame value of the canvaseso on the right
# for example, if frame "3" was deleted, then "4" would have to become "3"
for i in range(frame, new_canvases.size()):
var c : Canvas = new_canvases[i]
Global.undo_redo.add_do_property(c, "frame", i)
Global.undo_redo.add_undo_property(c, "frame", c.frame)
Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases)
Global.undo_redo.add_undo_property(Global, "canvas", canvas)
Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame)
Global.undo_redo.add_undo_property(Global, "animation_tags", Global.animation_tags)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_do_method(Global, "redo", [canvas])
Global.undo_redo.add_undo_method(Global, "undo", [canvas])
Global.undo_redo.commit_action()
func _on_CopyFrame_pressed(frame := -1) -> void:
if frame == -1:
frame = Global.current_frame
var canvas : Canvas = Global.canvases[frame]
var new_canvas : Canvas = load("res://src/Canvas.tscn").instance()
new_canvas.size = Global.canvas.size
new_canvas.frame = Global.canvases.size()
var new_canvases := Global.canvases.duplicate()
new_canvases.insert(frame + 1, new_canvas)
for layer in canvas.layers: # Copy every layer
var sprite := Image.new()
sprite.copy_from(layer[0])
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
new_canvas.layers.append([sprite, tex, layer[2]])
var new_animation_tags := Global.animation_tags.duplicate(true)
# Loop through the tags to see if the frame is in one
for tag in new_animation_tags:
if frame + 1 >= tag[2] && frame + 1 <= tag[3]:
tag[3] += 1
Global.undos += 1
Global.undo_redo.create_action("Add Frame")
Global.undo_redo.add_do_method(Global, "redo", [new_canvas])
Global.undo_redo.add_undo_method(Global, "undo", [new_canvas])
Global.undo_redo.add_do_property(Global, "canvases", new_canvases)
Global.undo_redo.add_do_property(Global, "canvas", new_canvas)
Global.undo_redo.add_do_property(Global, "current_frame", frame + 1)
Global.undo_redo.add_do_property(Global, "animation_tags", new_animation_tags)
for i in range(Global.layers.size()):
for child in Global.layers[i][3].get_children():
Global.undo_redo.add_do_property(child, "pressed", false)
Global.undo_redo.add_undo_property(child, "pressed", child.pressed)
for c in Global.canvases:
Global.undo_redo.add_do_property(c, "visible", false)
Global.undo_redo.add_undo_property(c, "visible", c.visible)
for i in range(frame, new_canvases.size()):
var c : Canvas = new_canvases[i]
Global.undo_redo.add_do_property(c, "frame", i)
Global.undo_redo.add_undo_property(c, "frame", c.frame)
Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases)
Global.undo_redo.add_undo_property(Global, "canvas", Global.canvas)
Global.undo_redo.add_undo_property(Global, "current_frame", frame)
Global.undo_redo.add_undo_property(Global, "animation_tags", Global.animation_tags)
Global.undo_redo.commit_action()
func _on_FrameTagButton_pressed() -> void:
Global.tag_dialog.popup_centered()
func _on_OnionSkinning_pressed() -> void:
Global.onion_skinning = !Global.onion_skinning
Global.canvas.update()
var theme_type := Global.theme_type
if theme_type == "Gold":
theme_type = "Light"
var texture_button : TextureRect = Global.onion_skinning_button.get_child(0)
if Global.onion_skinning:
texture_button.texture = load("res://Assets/Graphics/%s Themes/Timeline/onion_skinning.png" % theme_type)
else:
texture_button.texture = load("res://Assets/Graphics/%s Themes/Timeline/onion_skinning_off.png" % theme_type)
func _on_OnionSkinningSettings_pressed() -> void:
$OnionSkinningSettings.popup(Rect2(Global.onion_skinning_button.rect_global_position.x - $OnionSkinningSettings.rect_size.x - 16, Global.onion_skinning_button.rect_global_position.y - 106, 136, 126))
func _on_LoopAnim_pressed() -> void:
var texture_button : TextureRect = Global.loop_animation_button.get_child(0)
var theme_type := Global.theme_type
if theme_type == "Gold":
theme_type = "Light"
match animation_loop:
0: # Make it loop
animation_loop = 1
texture_button.texture = load("res://Assets/Graphics/%s Themes/Timeline/loop.png" % theme_type)
Global.loop_animation_button.hint_tooltip = "Cycle loop"
1: # Make it ping-pong
animation_loop = 2
texture_button.texture = load("res://Assets/Graphics/%s Themes/Timeline/loop_pingpong.png" % theme_type)
Global.loop_animation_button.hint_tooltip = "Ping-pong loop"
2: # Make it stop
animation_loop = 0
texture_button.texture = load("res://Assets/Graphics/%s Themes/Timeline/loop_none.png" % theme_type)
Global.loop_animation_button.hint_tooltip = "No loop"
func _on_PlayForward_toggled(button_pressed : bool) -> void:
var theme_type := Global.theme_type
if theme_type == "Gold":
theme_type = "Light"
if button_pressed:
Global.play_forward.get_child(0).texture = load("res://Assets/Graphics/%s Themes/Timeline/pause.png" % theme_type)
else:
Global.play_forward.get_child(0).texture = load("res://Assets/Graphics/%s Themes/Timeline/play.png" % theme_type)
play_animation(button_pressed, true)
func _on_PlayBackwards_toggled(button_pressed : bool) -> void:
var theme_type := Global.theme_type
if theme_type == "Gold":
theme_type = "Light"
if button_pressed:
Global.play_backwards.get_child(0).texture = load("res://Assets/Graphics/%s Themes/Timeline/pause.png" % theme_type)
else:
Global.play_backwards.get_child(0).texture = load("res://Assets/Graphics/%s Themes/Timeline/play_backwards.png" % theme_type)
play_animation(button_pressed, false)
func _on_AnimationTimer_timeout() -> void:
if animation_forward:
if Global.current_frame < last_frame:
Global.current_frame += 1
else:
match animation_loop:
0: # No loop
Global.play_forward.pressed = false
Global.play_backwards.pressed = false
Global.animation_timer.stop()
1: # Cycle loop
Global.current_frame = first_frame
2: # Ping pong loop
animation_forward = false
_on_AnimationTimer_timeout()
else:
if Global.current_frame > first_frame:
Global.current_frame -= 1
else:
match animation_loop:
0: # No loop
Global.play_backwards.pressed = false
Global.play_forward.pressed = false
Global.animation_timer.stop()
1: # Cycle loop
Global.current_frame = last_frame
2: # Ping pong loop
animation_forward = true
_on_AnimationTimer_timeout()
func play_animation(play : bool, forward_dir : bool) -> void:
var theme_type := Global.theme_type
if theme_type == "Gold":
theme_type = "Light"
if forward_dir:
Global.play_backwards.disconnect("toggled", self, "_on_PlayBackwards_toggled")
Global.play_backwards.pressed = false
Global.play_backwards.get_child(0).texture = load("res://Assets/Graphics/%s Themes/Timeline/play_backwards.png" % theme_type)
Global.play_backwards.connect("toggled", self, "_on_PlayBackwards_toggled")
else:
Global.play_forward.disconnect("toggled", self, "_on_PlayForward_toggled")
Global.play_forward.pressed = false
Global.play_forward.get_child(0).texture = load("res://Assets/Graphics/%s Themes/Timeline/play.png" % theme_type)
Global.play_forward.connect("toggled", self, "_on_PlayForward_toggled")
if Global.canvases.size() == 1:
if forward_dir:
Global.play_forward.pressed = false
else:
Global.play_backwards.pressed = false
return
first_frame = 0
last_frame = Global.canvases.size() - 1
if Global.play_only_tags:
for tag in Global.animation_tags:
if Global.current_frame + 1 >= tag[2] && Global.current_frame + 1 <= tag[3]:
first_frame = tag[2] - 1
last_frame = min(Global.canvases.size() - 1, tag[3] - 1)
if play:
Global.animation_timer.wait_time = 1 / fps
Global.animation_timer.start()
animation_forward = forward_dir
else:
Global.animation_timer.stop()
func _on_NextFrame_pressed() -> void:
if Global.current_frame < Global.canvases.size() - 1:
Global.current_frame += 1
func _on_PreviousFrame_pressed() -> void:
if Global.current_frame > 0:
Global.current_frame -= 1
func _on_LastFrame_pressed() -> void:
Global.current_frame = Global.canvases.size() - 1
func _on_FirstFrame_pressed() -> void:
Global.current_frame = 0
func _on_FPSValue_value_changed(value : float) -> void:
fps = float(value)
Global.animation_timer.wait_time = 1 / fps
func _on_PastOnionSkinning_value_changed(value : float) -> void:
Global.onion_skinning_past_rate = int(value)
Global.canvas.update()
func _on_FutureOnionSkinning_value_changed(value : float) -> void:
Global.onion_skinning_future_rate = int(value)
Global.canvas.update()
func _on_BlueRedMode_toggled(button_pressed : bool) -> void:
Global.onion_skinning_blue_red = button_pressed
Global.canvas.update()
# Layer buttons
func add_layer(is_new := true) -> void:
var layer_name = null
if !is_new: # Clone layer
layer_name = Global.layers[Global.current_layer][0] + " (" + tr("copy") + ")"
var new_layers : Array = Global.layers.duplicate()
# Store [Layer name (0), Layer visibility boolean (1), Layer lock boolean (2), Frame container (3),
# will new frames be linked boolean (4), Array of linked frames (5)]
new_layers.append([layer_name, true, false, HBoxContainer.new(), false, []])
Global.undos += 1
Global.undo_redo.create_action("Add Layer")
for c in Global.canvases:
var new_layer := Image.new()
if is_new:
new_layer.create(c.size.x, c.size.y, false, Image.FORMAT_RGBA8)
else: # Clone layer
new_layer.copy_from(c.layers[Global.current_layer][0])
new_layer.lock()
var new_layer_tex := ImageTexture.new()
new_layer_tex.create_from_image(new_layer, 0)
var new_canvas_layers : Array = c.layers.duplicate()
# Store [Image, ImageTexture, Opacity]
new_canvas_layers.append([new_layer, new_layer_tex, 1])
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers)
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer + 1)
Global.undo_redo.add_do_property(Global, "layers", new_layers)
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
Global.undo_redo.commit_action()
func _on_RemoveLayer_pressed() -> void:
var new_layers : Array = Global.layers.duplicate()
new_layers.remove(Global.current_layer)
Global.undos += 1
Global.undo_redo.create_action("Remove Layer")
if Global.current_layer > 0:
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer - 1)
else:
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer)
for c in Global.canvases:
var new_canvas_layers : Array = c.layers.duplicate()
new_canvas_layers.remove(Global.current_layer)
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers)
Global.undo_redo.add_do_property(Global, "layers", new_layers)
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
Global.undo_redo.commit_action()
func change_layer_order(rate : int) -> void:
var change = Global.current_layer + rate
var new_layers : Array = Global.layers.duplicate()
var temp = new_layers[Global.current_layer]
new_layers[Global.current_layer] = new_layers[change]
new_layers[change] = temp
Global.undo_redo.create_action("Change Layer Order")
for c in Global.canvases:
var new_layers_canvas : Array = c.layers.duplicate()
var temp_canvas = new_layers_canvas[Global.current_layer]
new_layers_canvas[Global.current_layer] = new_layers_canvas[change]
new_layers_canvas[change] = temp_canvas
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas)
Global.undo_redo.add_undo_property(c, "layers", c.layers)
Global.undo_redo.add_do_property(Global, "current_layer", change)
Global.undo_redo.add_do_property(Global, "layers", new_layers)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvas])
Global.undo_redo.add_do_method(Global, "redo", [Global.canvas])
Global.undo_redo.commit_action()
func _on_MergeDownLayer_pressed() -> void:
var new_layers : Array = Global.layers.duplicate(true)
Global.undos += 1
Global.undo_redo.create_action("Merge Layer")
for c in Global.canvases:
var new_layers_canvas : Array = c.layers.duplicate(true)
var selected_layer := Image.new()
selected_layer.copy_from(new_layers_canvas[Global.current_layer][0])
selected_layer.lock()
if c.layers[Global.current_layer][2] < 1: # If we have layer transparency
for xx in selected_layer.get_size().x:
for yy in selected_layer.get_size().y:
var pixel_color : Color = selected_layer.get_pixel(xx, yy)
var alpha : float = pixel_color.a * c.layers[Global.current_layer][2]
selected_layer.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha))
var new_layer := Image.new()
new_layer.copy_from(c.layers[Global.current_layer - 1][0])
new_layer.lock()
c.blend_rect(new_layer, selected_layer, Rect2(c.position, c.size), Vector2.ZERO)
new_layers_canvas.remove(Global.current_layer)
if !selected_layer.is_invisible() and Global.layers[Global.current_layer - 1][5].size() > 1 and (c in Global.layers[Global.current_layer - 1][5]):
new_layers[Global.current_layer - 1][5].erase(c)
var tex := ImageTexture.new()
tex.create_from_image(new_layer, 0)
new_layers_canvas[Global.current_layer - 1][0] = new_layer
new_layers_canvas[Global.current_layer - 1][1] = tex
else:
Global.undo_redo.add_do_property(c.layers[Global.current_layer - 1][0], "data", new_layer.data)
Global.undo_redo.add_undo_property(c.layers[Global.current_layer - 1][0], "data", c.layers[Global.current_layer - 1][0].data)
Global.undo_redo.add_do_property(c, "layers", new_layers_canvas)
Global.undo_redo.add_undo_property(c, "layers", c.layers)
new_layers.remove(Global.current_layer)
Global.undo_redo.add_do_property(Global, "current_layer", Global.current_layer - 1)
Global.undo_redo.add_do_property(Global, "layers", new_layers)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_undo_property(Global, "current_layer", Global.current_layer)
Global.undo_redo.add_undo_method(Global, "undo", Global.canvases)
Global.undo_redo.add_do_method(Global, "redo", Global.canvases)
Global.undo_redo.commit_action()
func _on_OpacitySlider_value_changed(value) -> void:
Global.canvas.layers[Global.current_layer][2] = value / 100
Global.layer_opacity_slider.value = value
Global.layer_opacity_slider.value = value
Global.layer_opacity_spinbox.value = value
Global.canvas.update()
func _on_OnionSkinningSettings_popup_hide() -> void:
Global.can_draw = true

View file

@ -0,0 +1,838 @@
[gd_scene load_steps=51 format=2]
[ext_resource path="res://src/UI/Timeline/AnimationTimeline.gd" type="Script" id=1]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/New_Layer.png" type="Texture" id=2]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/New_Layer_Hover.png" type="Texture" id=3]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Delete_Layer.png" type="Texture" id=4]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Delete_Layer_Hover.png" type="Texture" id=5]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Delete_Layer_Disabled.png" type="Texture" id=6]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Move_Up.png" type="Texture" id=7]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Move_Up_Hover.png" type="Texture" id=8]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Move_Up_Disabled.png" type="Texture" id=9]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Move_Down.png" type="Texture" id=10]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Move_Down_Hover.png" type="Texture" id=11]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Move_Down_Disabled.png" type="Texture" id=12]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Clone_Layer.png" type="Texture" id=13]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Clone_Layer_Hover.png" type="Texture" id=14]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Merge_Down.png" type="Texture" id=15]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Merge_Down_Hover.png" type="Texture" id=16]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Merge_Down_Disabled.png" type="Texture" id=17]
[ext_resource path="res://src/UI/Timeline/LayerButton.tscn" type="PackedScene" id=18]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/new_frame.png" type="Texture" id=19]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/remove_frame.png" type="Texture" id=20]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/go_to_first_frame.png" type="Texture" id=21]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/play.png" type="Texture" id=22]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/previous_frame.png" type="Texture" id=23]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/play_backwards.png" type="Texture" id=24]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/go_to_last_frame.png" type="Texture" id=25]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/next_frame.png" type="Texture" id=26]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/copy_frame.png" type="Texture" id=27]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/tag.png" type="Texture" id=28]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/onion_skinning_off.png" type="Texture" id=29]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/expandable.png" type="Texture" id=30]
[ext_resource path="res://Assets/Graphics/Dark Themes/Timeline/loop.png" type="Texture" id=31]
[ext_resource path="res://src/UI/Dialogs/FrameTagDialog.tscn" type="PackedScene" id=42]
[sub_resource type="InputEventKey" id=1]
control = true
command = true
scancode = 16777229
[sub_resource type="ShortCut" id=2]
shortcut = SubResource( 1 )
[sub_resource type="InputEventKey" id=3]
control = true
command = true
scancode = 16777231
[sub_resource type="ShortCut" id=4]
shortcut = SubResource( 3 )
[sub_resource type="InputEventKey" id=5]
scancode = 16777247
[sub_resource type="ShortCut" id=6]
shortcut = SubResource( 5 )
[sub_resource type="InputEventKey" id=7]
scancode = 16777248
[sub_resource type="ShortCut" id=8]
shortcut = SubResource( 7 )
[sub_resource type="InputEventKey" id=9]
control = true
command = true
scancode = 16777233
[sub_resource type="ShortCut" id=10]
shortcut = SubResource( 9 )
[sub_resource type="InputEventKey" id=11]
control = true
command = true
scancode = 16777230
[sub_resource type="ShortCut" id=12]
shortcut = SubResource( 11 )
[sub_resource type="StyleBoxEmpty" id=13]
[sub_resource type="StyleBoxEmpty" id=14]
[sub_resource type="StyleBoxEmpty" id=15]
[sub_resource type="StyleBoxEmpty" id=16]
[sub_resource type="StyleBoxEmpty" id=17]
[sub_resource type="Theme" id=18]
HScrollBar/icons/decrement = null
HScrollBar/icons/decrement_highlight = null
HScrollBar/icons/increment = null
HScrollBar/icons/increment_highlight = null
HScrollBar/styles/grabber = SubResource( 13 )
HScrollBar/styles/grabber_highlight = SubResource( 14 )
HScrollBar/styles/grabber_pressed = SubResource( 15 )
HScrollBar/styles/scroll = SubResource( 16 )
HScrollBar/styles/scroll_focus = SubResource( 17 )
[node name="AnimationTimeline" type="Panel"]
margin_top = 438.0
margin_right = 704.0
margin_bottom = 620.0
rect_min_size = Vector2( 0, 200 )
size_flags_horizontal = 3
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="AnimationContainer" type="HBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="ForLayerButtons" type="VBoxContainer" parent="AnimationContainer"]
margin_right = 68.0
margin_bottom = 200.0
[node name="SpacerControl" type="Control" parent="AnimationContainer/ForLayerButtons"]
margin_right = 68.0
margin_bottom = 30.0
rect_min_size = Vector2( 0, 30 )
[node name="LayerButtons" type="GridContainer" parent="AnimationContainer/ForLayerButtons"]
margin_top = 34.0
margin_right = 68.0
margin_bottom = 138.0
size_flags_vertical = 0
custom_constants/vseparation = 4
custom_constants/hseparation = 4
columns = 2
[node name="AddLayer" type="TextureButton" parent="AnimationContainer/ForLayerButtons/LayerButtons" groups=[
"UIButtons",
]]
margin_right = 32.0
margin_bottom = 32.0
hint_tooltip = "Create a new layer"
focus_mode = 0
mouse_default_cursor_shape = 2
texture_normal = ExtResource( 2 )
texture_hover = ExtResource( 3 )
[node name="RemoveLayer" type="TextureButton" parent="AnimationContainer/ForLayerButtons/LayerButtons" groups=[
"UIButtons",
]]
margin_left = 36.0
margin_right = 68.0
margin_bottom = 32.0
hint_tooltip = "Remove current layer"
focus_mode = 0
mouse_default_cursor_shape = 8
disabled = true
texture_normal = ExtResource( 4 )
texture_hover = ExtResource( 5 )
texture_disabled = ExtResource( 6 )
[node name="MoveUpLayer" type="TextureButton" parent="AnimationContainer/ForLayerButtons/LayerButtons" groups=[
"UIButtons",
]]
margin_top = 36.0
margin_right = 32.0
margin_bottom = 68.0
hint_tooltip = "Move up the current layer"
focus_mode = 0
mouse_default_cursor_shape = 8
disabled = true
texture_normal = ExtResource( 7 )
texture_hover = ExtResource( 8 )
texture_disabled = ExtResource( 9 )
[node name="MoveDownLayer" type="TextureButton" parent="AnimationContainer/ForLayerButtons/LayerButtons" groups=[
"UIButtons",
]]
margin_left = 36.0
margin_top = 36.0
margin_right = 68.0
margin_bottom = 68.0
hint_tooltip = "Move down the current layer"
focus_mode = 0
mouse_default_cursor_shape = 8
disabled = true
texture_normal = ExtResource( 10 )
texture_hover = ExtResource( 11 )
texture_disabled = ExtResource( 12 )
[node name="CloneLayer" type="TextureButton" parent="AnimationContainer/ForLayerButtons/LayerButtons" groups=[
"UIButtons",
]]
margin_top = 72.0
margin_right = 32.0
margin_bottom = 104.0
hint_tooltip = "Clone current layer"
focus_mode = 0
mouse_default_cursor_shape = 2
texture_normal = ExtResource( 13 )
texture_hover = ExtResource( 14 )
[node name="MergeDownLayer" type="TextureButton" parent="AnimationContainer/ForLayerButtons/LayerButtons" groups=[
"UIButtons",
]]
margin_left = 36.0
margin_top = 72.0
margin_right = 68.0
margin_bottom = 104.0
hint_tooltip = "Merge current layer with the one below"
focus_mode = 0
mouse_default_cursor_shape = 8
disabled = true
texture_normal = ExtResource( 15 )
texture_hover = ExtResource( 16 )
texture_disabled = ExtResource( 17 )
[node name="SpacerControl" type="Control" parent="AnimationContainer"]
margin_left = 72.0
margin_right = 88.0
margin_bottom = 200.0
rect_min_size = Vector2( 16, 0 )
[node name="TimelineContainer" type="VBoxContainer" parent="AnimationContainer"]
margin_left = 92.0
margin_right = 696.0
margin_bottom = 200.0
size_flags_horizontal = 3
[node name="SpacerControl" type="Control" parent="AnimationContainer/TimelineContainer"]
margin_right = 604.0
[node name="AnimationButtons" type="HBoxContainer" parent="AnimationContainer/TimelineContainer"]
margin_top = 4.0
margin_right = 604.0
margin_bottom = 28.0
rect_min_size = Vector2( 0, 24 )
[node name="CurrentFrame" type="Label" parent="AnimationContainer/TimelineContainer/AnimationButtons"]
margin_top = 5.0
margin_right = 150.0
margin_bottom = 19.0
rect_min_size = Vector2( 150, 0 )
text = "Current frame: 1/1"
[node name="AddFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons" groups=[
"UIButtons",
]]
margin_left = 154.0
margin_right = 174.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Add a new frame"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/AddFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -6.0
margin_top = -6.0
margin_right = 6.0
margin_bottom = 6.0
texture = ExtResource( 19 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="DeleteFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons" groups=[
"UIButtons",
]]
margin_left = 178.0
margin_right = 198.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Remove Frame"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/DeleteFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -6.0
margin_top = -1.0
margin_right = 6.0
margin_bottom = 1.0
size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource( 20 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CopyFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons" groups=[
"UIButtons",
]]
margin_left = 202.0
margin_right = 222.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Clone Frame"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/CopyFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -5.0
margin_top = -7.0
margin_right = 5.0
margin_bottom = 7.0
texture = ExtResource( 27 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="FrameTagButton" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons" groups=[
"UIButtons",
]]
margin_left = 226.0
margin_right = 246.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Manage frame tags"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/FrameTagButton"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -7.0
margin_top = -7.0
margin_right = 7.0
margin_bottom = 7.0
texture = ExtResource( 28 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PlaybackButtons" type="HBoxContainer" parent="AnimationContainer/TimelineContainer/AnimationButtons"]
margin_left = 286.0
margin_right = 426.0
margin_bottom = 24.0
size_flags_horizontal = 6
[node name="FirstFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons" groups=[
"UIButtons",
]]
margin_right = 20.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "FIRSTFRAME_HT"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
shortcut_in_tooltip = false
shortcut = SubResource( 2 )
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/FirstFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -5.5
margin_top = -6.0
margin_right = 5.5
margin_bottom = 6.0
texture = ExtResource( 21 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PreviousFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons" groups=[
"UIButtons",
]]
margin_left = 24.0
margin_right = 44.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "PREVIOUSFRAME_HT"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
shortcut_in_tooltip = false
shortcut = SubResource( 4 )
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/PreviousFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -5.5
margin_top = -6.0
margin_right = 5.5
margin_bottom = 6.0
texture = ExtResource( 23 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PlayBackwards" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons" groups=[
"UIButtons",
]]
margin_left = 48.0
margin_right = 68.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "PLAYBACKWARDS_HT"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
toggle_mode = true
shortcut_in_tooltip = false
shortcut = SubResource( 6 )
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/PlayBackwards"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -4.0
margin_top = -6.0
margin_right = 3.0
margin_bottom = 6.0
texture = ExtResource( 24 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PlayForward" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons" groups=[
"UIButtons",
]]
margin_left = 72.0
margin_right = 92.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "PLAYFORWARD_HT"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
toggle_mode = true
shortcut_in_tooltip = false
shortcut = SubResource( 8 )
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/PlayForward"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -3.5
margin_top = -6.0
margin_right = 3.5
margin_bottom = 6.0
texture = ExtResource( 22 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="NextFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons" groups=[
"UIButtons",
]]
margin_left = 96.0
margin_right = 116.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "NEXTFRAME_HT"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
shortcut_in_tooltip = false
shortcut = SubResource( 10 )
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/NextFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -5.5
margin_top = -6.0
margin_right = 5.5
margin_bottom = 6.0
texture = ExtResource( 26 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LastFrame" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons" groups=[
"UIButtons",
]]
margin_left = 120.0
margin_right = 140.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "LASTFRAME_HT"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
shortcut_in_tooltip = false
shortcut = SubResource( 12 )
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/LastFrame"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -5.5
margin_top = -6.0
margin_right = 5.5
margin_bottom = 6.0
texture = ExtResource( 25 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LoopButtons" type="HBoxContainer" parent="AnimationContainer/TimelineContainer/AnimationButtons"]
margin_left = 466.0
margin_right = 604.0
margin_bottom = 24.0
size_flags_horizontal = 0
[node name="OnionSkinningSettings" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons" groups=[
"UIButtons",
]]
margin_right = 12.0
margin_bottom = 20.0
hint_tooltip = "Onion Skinning settings"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/OnionSkinningSettings"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -3.0
margin_top = -6.0
margin_right = 3.0
margin_bottom = 6.0
size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource( 30 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="OnionSkinning" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons" groups=[
"UIButtons",
]]
margin_left = 16.0
margin_right = 36.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Enable/disable Onion Skinning"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/OnionSkinning"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -7.0
margin_top = -7.0
margin_right = 7.0
margin_bottom = 7.0
size_flags_horizontal = 0
size_flags_vertical = 0
texture = ExtResource( 29 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LoopAnim" type="Button" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons" groups=[
"UIButtons",
]]
margin_left = 40.0
margin_right = 60.0
margin_bottom = 20.0
rect_min_size = Vector2( 20, 0 )
hint_tooltip = "Cycle loop"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_vertical = 0
[node name="TextureRect" type="TextureRect" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/LoopAnim"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -7.0
margin_top = -7.0
margin_right = 7.0
margin_bottom = 7.0
texture = ExtResource( 31 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="FPSValue" type="SpinBox" parent="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons"]
margin_left = 64.0
margin_right = 138.0
margin_bottom = 24.0
hint_tooltip = "How many frames per second should the animation preview be?
The more FPS, the faster the animation plays."
mouse_default_cursor_shape = 2
min_value = 0.1
step = 0.1
value = 6.0
align = 1
suffix = "FPS"
[node name="HSeparator" type="HSeparator" parent="AnimationContainer/TimelineContainer"]
margin_top = 32.0
margin_right = 604.0
margin_bottom = 36.0
[node name="OpacityAndTagContainer" type="HBoxContainer" parent="AnimationContainer/TimelineContainer"]
margin_top = 40.0
margin_right = 604.0
margin_bottom = 72.0
custom_constants/separation = 2
[node name="OpacityContainer" type="HBoxContainer" parent="AnimationContainer/TimelineContainer/OpacityAndTagContainer"]
margin_right = 214.0
margin_bottom = 32.0
rect_min_size = Vector2( 214, 0 )
[node name="OpacityLabel" type="Label" parent="AnimationContainer/TimelineContainer/OpacityAndTagContainer/OpacityContainer"]
margin_right = 53.0
margin_bottom = 32.0
size_flags_horizontal = 0
size_flags_vertical = 1
text = "Opacity:"
valign = 1
[node name="OpacitySlider" type="HSlider" parent="AnimationContainer/TimelineContainer/OpacityAndTagContainer/OpacityContainer"]
margin_left = 57.0
margin_right = 136.0
margin_bottom = 32.0
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 3
size_flags_vertical = 1
value = 100.0
ticks_on_borders = true
[node name="OpacitySpinBox" type="SpinBox" parent="AnimationContainer/TimelineContainer/OpacityAndTagContainer/OpacityContainer"]
margin_left = 140.0
margin_top = 4.0
margin_right = 214.0
margin_bottom = 28.0
mouse_default_cursor_shape = 2
size_flags_vertical = 4
value = 100.0
align = 1
[node name="TagScroll" type="ScrollContainer" parent="AnimationContainer/TimelineContainer/OpacityAndTagContainer"]
margin_left = 216.0
margin_right = 604.0
margin_bottom = 32.0
rect_min_size = Vector2( 0, 32 )
size_flags_horizontal = 3
theme = SubResource( 18 )
scroll_vertical_enabled = false
[node name="TagContainer" type="Control" parent="AnimationContainer/TimelineContainer/OpacityAndTagContainer/TagScroll"]
[node name="TimelineScroll" type="ScrollContainer" parent="AnimationContainer/TimelineContainer"]
margin_top = 76.0
margin_right = 604.0
margin_bottom = 200.0
size_flags_vertical = 3
[node name="LayersAndFrames" type="HBoxContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll"]
margin_right = 252.0
margin_bottom = 124.0
size_flags_vertical = 3
[node name="LayerVBoxCont" type="VBoxContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames"]
margin_right = 212.0
margin_bottom = 124.0
[node name="LayerLabel" type="Label" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames/LayerVBoxCont"]
margin_right = 212.0
margin_bottom = 16.0
rect_min_size = Vector2( 0, 16 )
text = "Layers"
align = 1
valign = 1
[node name="LayersContainer" type="VBoxContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames/LayerVBoxCont"]
margin_top = 20.0
margin_right = 212.0
margin_bottom = 56.0
[node name="LayerContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames/LayerVBoxCont/LayersContainer" instance=ExtResource( 18 )]
margin_right = 212.0
[node name="FrameButtonsAndIds" type="VBoxContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames"]
margin_left = 216.0
margin_right = 252.0
margin_bottom = 124.0
[node name="FrameIDs" type="HBoxContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames/FrameButtonsAndIds"]
margin_right = 36.0
margin_bottom = 16.0
rect_min_size = Vector2( 0, 16 )
[node name="Label" type="Label" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames/FrameButtonsAndIds/FrameIDs"]
margin_top = 1.0
margin_right = 36.0
margin_bottom = 15.0
rect_min_size = Vector2( 36, 0 )
text = "1"
align = 1
[node name="FramesContainer" type="VBoxContainer" parent="AnimationContainer/TimelineContainer/TimelineScroll/LayersAndFrames/FrameButtonsAndIds"]
margin_top = 20.0
margin_right = 36.0
margin_bottom = 20.0
[node name="VSeparator" type="VSeparator" parent="AnimationContainer"]
margin_left = 700.0
margin_right = 704.0
margin_bottom = 200.0
[node name="AnimationTimer" type="Timer" parent="."]
[node name="OnionSkinningSettings" type="WindowDialog" parent="."]
rect_min_size = Vector2( 220, 126 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="OnionSkinningButtons" type="VBoxContainer" parent="OnionSkinningSettings"]
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
margin_left = 4.0
margin_top = -58.0
margin_right = -4.0
margin_bottom = 58.0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="OnionSkinningPast" type="Label" parent="OnionSkinningSettings/OnionSkinningButtons"]
margin_right = 212.0
margin_bottom = 14.0
text = "Past Frames"
[node name="PastOnionSkinning" type="SpinBox" parent="OnionSkinningSettings/OnionSkinningButtons"]
margin_top = 18.0
margin_right = 212.0
margin_bottom = 42.0
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
align = 1
[node name="OnionSkinningFuture" type="Label" parent="OnionSkinningSettings/OnionSkinningButtons"]
margin_top = 46.0
margin_right = 212.0
margin_bottom = 60.0
text = "Future Frames"
[node name="FutureOnionSkinning" type="SpinBox" parent="OnionSkinningSettings/OnionSkinningButtons"]
margin_top = 64.0
margin_right = 212.0
margin_bottom = 88.0
mouse_default_cursor_shape = 2
min_value = 1.0
value = 1.0
align = 1
[node name="BlueRedMode" type="CheckBox" parent="OnionSkinningSettings/OnionSkinningButtons"]
margin_top = 92.0
margin_right = 212.0
margin_bottom = 116.0
mouse_default_cursor_shape = 2
text = "Blue-Red Mode"
[node name="FrameTagDialog" parent="." instance=ExtResource( 42 )]
[connection signal="pressed" from="AnimationContainer/ForLayerButtons/LayerButtons/AddLayer" to="." method="add_layer" binds= [ true ]]
[connection signal="pressed" from="AnimationContainer/ForLayerButtons/LayerButtons/RemoveLayer" to="." method="_on_RemoveLayer_pressed"]
[connection signal="pressed" from="AnimationContainer/ForLayerButtons/LayerButtons/MoveUpLayer" to="." method="change_layer_order" binds= [ 1 ]]
[connection signal="pressed" from="AnimationContainer/ForLayerButtons/LayerButtons/MoveDownLayer" to="." method="change_layer_order" binds= [ -1 ]]
[connection signal="pressed" from="AnimationContainer/ForLayerButtons/LayerButtons/CloneLayer" to="." method="add_layer" binds= [ false ]]
[connection signal="pressed" from="AnimationContainer/ForLayerButtons/LayerButtons/MergeDownLayer" to="." method="_on_MergeDownLayer_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/AddFrame" to="." method="add_frame"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/DeleteFrame" to="." method="_on_DeleteFrame_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/CopyFrame" to="." method="_on_CopyFrame_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/FrameTagButton" to="." method="_on_FrameTagButton_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/FirstFrame" to="." method="_on_FirstFrame_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/PreviousFrame" to="." method="_on_PreviousFrame_pressed"]
[connection signal="toggled" from="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/PlayBackwards" to="." method="_on_PlayBackwards_toggled"]
[connection signal="toggled" from="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/PlayForward" to="." method="_on_PlayForward_toggled"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/NextFrame" to="." method="_on_NextFrame_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/PlaybackButtons/LastFrame" to="." method="_on_LastFrame_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/OnionSkinningSettings" to="." method="_on_OnionSkinningSettings_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/OnionSkinning" to="." method="_on_OnionSkinning_pressed"]
[connection signal="pressed" from="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/LoopAnim" to="." method="_on_LoopAnim_pressed"]
[connection signal="value_changed" from="AnimationContainer/TimelineContainer/AnimationButtons/LoopButtons/FPSValue" to="." method="_on_FPSValue_value_changed"]
[connection signal="value_changed" from="AnimationContainer/TimelineContainer/OpacityAndTagContainer/OpacityContainer/OpacitySlider" to="." method="_on_OpacitySlider_value_changed"]
[connection signal="value_changed" from="AnimationContainer/TimelineContainer/OpacityAndTagContainer/OpacityContainer/OpacitySpinBox" to="." method="_on_OpacitySlider_value_changed"]
[connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"]
[connection signal="popup_hide" from="OnionSkinningSettings" to="." method="_on_OnionSkinningSettings_popup_hide"]
[connection signal="value_changed" from="OnionSkinningSettings/OnionSkinningButtons/PastOnionSkinning" to="." method="_on_PastOnionSkinning_value_changed"]
[connection signal="value_changed" from="OnionSkinningSettings/OnionSkinningButtons/FutureOnionSkinning" to="." method="_on_FutureOnionSkinning_value_changed"]
[connection signal="toggled" from="OnionSkinningSettings/OnionSkinningButtons/BlueRedMode" to="." method="_on_BlueRedMode_toggled"]

View file

@ -0,0 +1,121 @@
extends Button
var frame := 0
var layer := 0
onready var popup_menu : PopupMenu = $PopupMenu
func _ready() -> void:
hint_tooltip = "Frame: %s, Layer: %s" % [frame + 1, layer]
if Global.canvases[frame] in Global.layers[layer][5]:
get_node("LinkedIndicator").visible = true
popup_menu.set_item_text(4, "Unlink Cel")
popup_menu.set_item_metadata(4, "Unlink Cel")
else:
get_node("LinkedIndicator").visible = false
popup_menu.set_item_text(4, "Link Cel")
popup_menu.set_item_metadata(4, "Link Cel")
func _on_CelButton_pressed() -> void:
if Input.is_action_just_released("left_mouse"):
Global.current_frame = frame
Global.current_layer = layer
elif Input.is_action_just_released("right_mouse"):
if Global.canvases.size() == 1:
popup_menu.set_item_disabled(0, true)
popup_menu.set_item_disabled(2, true)
popup_menu.set_item_disabled(3, true)
else:
popup_menu.set_item_disabled(0, false)
if frame > 0:
popup_menu.set_item_disabled(2, false)
if frame < Global.canvases.size() - 1:
popup_menu.set_item_disabled(3, false)
popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE))
pressed = !pressed
elif Input.is_action_just_released("middle_mouse"): # Middle mouse click
pressed = !pressed
Global.animation_timeline._on_DeleteFrame_pressed(frame)
else: # An example of this would be Space
pressed = !pressed
func _on_PopupMenu_id_pressed(ID : int) -> void:
match ID:
0: # Remove Frame
Global.animation_timeline._on_DeleteFrame_pressed(frame)
1: # Clone Frame
Global.animation_timeline._on_CopyFrame_pressed(frame)
2: # Move Left
change_frame_order(-1)
3: # Move Right
change_frame_order(1)
4: # Unlink Cel
var cel_index : int = Global.layers[layer][5].find(Global.canvases[frame])
var c = Global.canvases[frame]
var new_layers := Global.layers.duplicate(true)
var new_canvas_layers : Array = c.layers.duplicate(true)
if popup_menu.get_item_metadata(4) == "Unlink Cel":
new_layers[layer][5].remove(cel_index)
var sprite := Image.new()
sprite.copy_from(Global.canvases[frame].layers[layer][0])
sprite.lock()
var tex := ImageTexture.new()
tex.create_from_image(sprite, 0)
new_canvas_layers[layer][0] = sprite
new_canvas_layers[layer][1] = tex
Global.undo_redo.create_action("Unlink Cel")
Global.undo_redo.add_do_property(Global, "layers", new_layers)
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers)
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvases[frame]], layer)
Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]], layer)
Global.undo_redo.commit_action()
elif popup_menu.get_item_metadata(4) == "Link Cel":
new_layers[layer][5].append(Global.canvases[frame])
Global.undo_redo.create_action("Link Cel")
Global.undo_redo.add_do_property(Global, "layers", new_layers)
if new_layers[layer][5].size() > 1:
# If there are already linked cels, set the current cel's image
# to the first linked cel's image
new_canvas_layers[layer][0] = new_layers[layer][5][0].layers[layer][0]
new_canvas_layers[layer][1] = new_layers[layer][5][0].layers[layer][1]
Global.undo_redo.add_do_property(c, "layers", new_canvas_layers)
Global.undo_redo.add_undo_property(c, "layers", c.layers)
Global.undo_redo.add_undo_property(Global, "layers", Global.layers)
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvases[frame]], layer)
Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]], layer)
Global.undo_redo.commit_action()
func change_frame_order(rate : int) -> void:
var change = frame + rate
var new_canvases := Global.canvases.duplicate()
var temp = new_canvases[frame]
new_canvases[frame] = new_canvases[change]
new_canvases[change] = temp
Global.undo_redo.create_action("Change Frame Order")
Global.undo_redo.add_do_property(Global, "canvases", new_canvases)
Global.undo_redo.add_do_property(Global.canvases[frame], "frame", change)
Global.undo_redo.add_do_property(Global.canvases[change], "frame", frame)
if Global.current_frame == frame:
Global.undo_redo.add_do_property(Global, "current_frame", change)
Global.undo_redo.add_undo_property(Global, "current_frame", Global.current_frame)
Global.undo_redo.add_undo_property(Global, "canvases", Global.canvases)
Global.undo_redo.add_undo_property(Global.canvases[frame], "frame", frame)
Global.undo_redo.add_undo_property(Global.canvases[change], "frame", change)
Global.undo_redo.add_undo_method(Global, "undo", [Global.canvases[frame]])
Global.undo_redo.add_do_method(Global, "redo", [Global.canvases[frame]])
Global.undo_redo.commit_action()

View file

@ -0,0 +1,49 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://src/UI/Timeline/CelButton.gd" type="Script" id=1]
[node name="CelButton" type="Button"]
margin_top = 18.0
margin_right = 36.0
margin_bottom = 54.0
rect_min_size = Vector2( 36, 36 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 0
toggle_mode = true
button_mask = 7
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="CelTexture" type="TextureRect" parent="."]
margin_left = 2.0
margin_top = 1.78536
margin_right = 34.0
margin_bottom = 33.7854
rect_min_size = Vector2( 32, 32 )
size_flags_horizontal = 0
size_flags_vertical = 0
expand = true
stretch_mode = 6
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PopupMenu" type="PopupMenu" parent="."]
margin_right = 20.0
margin_bottom = 20.0
mouse_default_cursor_shape = 2
items = [ "Remove Frame", null, 0, false, true, -1, 0, null, "", false, "Clone Frame", null, 0, false, false, -1, 0, null, "", false, "Move Left", null, 0, false, true, -1, 0, null, "", false, "Move Right", null, 0, false, true, -1, 0, null, "", false, "Link Cel", null, 0, false, false, -1, 0, null, "", false ]
[node name="LinkedIndicator" type="Polygon2D" parent="."]
visible = false
color = Color( 0.0627451, 0.741176, 0.215686, 1 )
invert_enable = true
invert_border = 1.0
polygon = PoolVector2Array( 0, 0, 36, 0, 36, 36, 0, 36 )
[connection signal="pressed" from="." to="." method="_on_CelButton_pressed"]
[connection signal="id_pressed" from="PopupMenu" to="." method="_on_PopupMenu_id_pressed"]

View file

@ -0,0 +1,80 @@
class_name LayerButton
extends Button
var i := 0
var visibility_button : BaseButton
var lock_button : BaseButton
var linked_button : BaseButton
var label : Label
var line_edit : LineEdit
func _ready() -> void:
visibility_button = Global.find_node_by_name(self, "VisibilityButton")
lock_button = Global.find_node_by_name(self, "LockButton")
linked_button = Global.find_node_by_name(self, "LinkButton")
label = Global.find_node_by_name(self, "Label")
line_edit = Global.find_node_by_name(self, "LineEdit")
if Global.layers[i][1]:
visibility_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Layer_Visible.png" % Global.theme_type)
visibility_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Layer_Visible_Hover.png" % Global.theme_type)
else:
visibility_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Layer_Invisible.png" % Global.theme_type)
visibility_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Layer_Invisible_Hover.png" % Global.theme_type)
if Global.layers[i][2]:
lock_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Lock.png" % Global.theme_type)
lock_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Lock_Hover.png" % Global.theme_type)
else:
lock_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Unlock.png" % Global.theme_type)
lock_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Unlock_Hover.png" % Global.theme_type)
if Global.layers[i][4]: # If new layers will be linked
linked_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Linked_Layer.png" % Global.theme_type)
linked_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Linked_Layer_Hover.png" % Global.theme_type)
else:
linked_button.texture_normal = load("res://Assets/Graphics/%s Themes/Layers/Unlinked_Layer.png" % Global.theme_type)
linked_button.texture_hover = load("res://Assets/Graphics/%s Themes/Layers/Unlinked_Layer_Hover.png" % Global.theme_type)
func _input(event : InputEvent) -> void:
if (event.is_action_released("ui_accept") or event.is_action_released("ui_cancel")) and line_edit.visible and event.scancode != KEY_SPACE:
save_layer_name(line_edit.text)
func _on_LayerContainer_pressed() -> void:
pressed = !pressed
label.visible = false
line_edit.visible = true
line_edit.editable = true
line_edit.grab_focus()
func _on_LineEdit_focus_exited() -> void:
save_layer_name(line_edit.text)
func save_layer_name(new_name : String) -> void:
label.visible = true
line_edit.visible = false
line_edit.editable = false
label.text = new_name
Global.layers_changed_skip = true
Global.layers[i][0] = new_name
func _on_VisibilityButton_pressed() -> void:
Global.layers[i][1] = !Global.layers[i][1]
Global.canvas.update()
func _on_LockButton_pressed() -> void:
Global.layers[i][2] = !Global.layers[i][2]
func _on_LinkButton_pressed() -> void:
Global.layers[i][4] = !Global.layers[i][4]
if Global.layers[i][4] && !Global.layers[i][5]:
Global.layers[i][5].append(Global.canvas)
Global.layers[i][3].get_child(Global.current_frame)._ready()

View file

@ -0,0 +1,120 @@
[gd_scene load_steps=8 format=2]
[ext_resource path="res://src/UI/Timeline/LayerButton.gd" type="Script" id=1]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Layer_Visible_Hover.png" type="Texture" id=2]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Unlock.png" type="Texture" id=3]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Unlinked_Layer.png" type="Texture" id=4]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Layer_Visible.png" type="Texture" id=5]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Unlock_Hover.png" type="Texture" id=6]
[ext_resource path="res://Assets/Graphics/Dark Themes/Layers/Unlinked_Layer_Hover.png" type="Texture" id=7]
[node name="LayerContainer" type="Button"]
margin_right = 210.0
margin_bottom = 36.0
rect_min_size = Vector2( 212, 36 )
size_flags_horizontal = 0
toggle_mode = true
action_mode = 0
script = ExtResource( 1 )
__meta__ = {
"_edit_horizontal_guides_": [ ],
"_edit_use_anchors_": false
}
[node name="HBoxContainer" type="HBoxContainer" parent="."]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 0
__meta__ = {
"_edit_use_anchors_": false
}
[node name="LayerButtons" type="HBoxContainer" parent="HBoxContainer"]
margin_right = 104.0
margin_bottom = 36.0
[node name="VisibilityButton" type="TextureButton" parent="HBoxContainer/LayerButtons" groups=[
"UIButtons",
]]
margin_top = 2.0
margin_right = 32.0
margin_bottom = 34.0
hint_tooltip = "Toggle layer's visibility"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 4
texture_normal = ExtResource( 5 )
texture_hover = ExtResource( 2 )
[node name="LockButton" type="TextureButton" parent="HBoxContainer/LayerButtons" groups=[
"UIButtons",
]]
margin_left = 36.0
margin_top = 2.0
margin_right = 68.0
margin_bottom = 34.0
hint_tooltip = "Lock/unlock layer"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 4
texture_normal = ExtResource( 3 )
texture_hover = ExtResource( 6 )
[node name="LinkButton" type="TextureButton" parent="HBoxContainer/LayerButtons" groups=[
"UIButtons",
]]
margin_left = 72.0
margin_top = 2.0
margin_right = 104.0
margin_bottom = 34.0
hint_tooltip = "Enable/disable cel linking
Linked cels are being shared across multiple frames"
focus_mode = 0
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
size_flags_vertical = 4
texture_normal = ExtResource( 4 )
texture_hover = ExtResource( 7 )
[node name="LayerName" type="HBoxContainer" parent="HBoxContainer"]
margin_left = 108.0
margin_right = 212.0
margin_bottom = 36.0
rect_min_size = Vector2( 104, 0 )
mouse_default_cursor_shape = 2
size_flags_horizontal = 0
alignment = 1
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Label" type="Label" parent="HBoxContainer/LayerName"]
margin_top = 11.0
margin_right = 104.0
margin_bottom = 25.0
size_flags_horizontal = 3
text = "Layer 0"
align = 1
clip_text = true
[node name="LineEdit" type="LineEdit" parent="HBoxContainer/LayerName"]
visible = false
margin_left = 86.0
margin_top = 5.0
margin_right = 166.0
margin_bottom = 37.0
rect_min_size = Vector2( 80, 32 )
size_flags_vertical = 4
text = "Layer 0"
editable = false
caret_blink = true
caret_blink_speed = 0.5
[connection signal="pressed" from="." to="." method="_on_LayerContainer_pressed"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/VisibilityButton" to="." method="_on_VisibilityButton_pressed"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/LockButton" to="." method="_on_LockButton_pressed"]
[connection signal="pressed" from="HBoxContainer/LayerButtons/LinkButton" to="." method="_on_LinkButton_pressed"]
[connection signal="focus_exited" from="HBoxContainer/LayerName/LineEdit" to="." method="_on_LineEdit_focus_exited"]

View file

@ -0,0 +1,8 @@
extends ColorRect
func _ready() -> void:
rect_size = Global.canvas.size
material.set_shader_param("size", Global.checker_size)
material.set_shader_param("color1", Global.checker_color_1)
material.set_shader_param("color2", Global.checker_color_2)