mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 09:09:47 +00:00
Basic Layer Groups and Timeline Refactor (#698)
* Fixed issues with Shading tool Saturation and Value not always being right in Hue Shading mode * Shading tool hue shifting fixes and tweaks * Bringing over changes from layer groups brach, without any changes to layer blending * Some quick fixes to make it work again * Fixed some of the places where GroupLayers cause errors. Cel Buttons are now hidden when groups are collapsed * Layer drag highlighting (need to actually drop them correctly, also need to do cels) * Added more layer hierarchy related functions, organized the function order in the Layer classes a bit * Switched the layer type changing from string to int * Moved layer type enum to Global * Added get_layer_type_name(), currently used for the default layer name * Renamed the layer get_children/is_a_parent_of functions * changed get_layer_type_name() to get_default_name(number) * New layer drag and dropping behavior * Added read/write_image_data_from/to_pxo functions to Cel classes to handle saving/loading the binary image data for each cel type * Fixed warning * Added a line to child layers wich makes it easier to see where they are in the hierarchy * Fixed debugger warning * Fixed all cel types loading as PixelCels * Fixed spacing issue with cels when collapsing groups * Fixed bug when dropping a child layer to the bottom region of its parent group, where it would end up to far down (maybe disappearing) * updated temporary todo comments * Created a base scene for layer buttons and merged layer button script into one * Prevent the case of parenting to itself in layer drag and drop, fixed static reference to LayerButton still being BaseLayerButton * Use a base scene for CelButtons * First bit of the refactoring work * Several bits of refactoring * Fixed moving cels * Cleaned up Project.move_cel function * Fixed project_layer_removed * Updated change_frame_order on FrameButton. Some (not all) work on getting the layer UI updated when pressing buttons such as collapse/visible/lock * Bug fixes. Updating layer button's buttons * Fixed timeline selection issues when creating a new project. Some code cleanup * tweaks * Removed a bunch of commented out code * Removing more commented out code * Fixed bugs with timeline selectio. Fixed cels being placed in the reverse layer order when adding a frame * Changed add/remove_frame to add/remove_frames (multiple support) * Refactored copy_frames in animation timeline * added copy function to cel classes * added layer copy function * simplifed copy_frames a tiny bit * Updated TODO comments to categorize them and remove any that were already done * Turned Project.add/remove_layer into Project.add/remove_layers (multiple support), not yet tested * Seperated the layer cloning functionality in timeline's add_layer to its own function, since they're only used by one button, renamed to _on_Button_pressed naming scheme, added children support to the delete layer button * some TODOs * Added layer swapping * Added priorities to refactor TODOs * Simplified layer swapping code a little * Fixed performance regression on changing project, updated TODOs * Included _on_MergeDownLayer_pressed in timeline refactor * Cleaned up _on_MergeDownLayer_pressed refactor * If all frames are selected, prevent being able to remove all of them * Fixed cel linking when cloning layers/frames. Moved the copy function from cel classes to layer classes, splitting into copy_cel and copy_all_cels * Combined and rewrote the 2 project _toggle_layer_buttons_.. functions into 1 simpler _toggle_layer_buttons function * Simplified _toggle_layer_buttons some more * Added hierarchy support for move up/down layer buttons * Added toggle_frame_buttons method to project (extracted from _frame_changed). Called from main when setting up startup project. Removed _ from start of _toggle_layer_buttons name * Fixed duplicate_layers parent references being to the original layers * cleaned up project.move_layers method a bit * TODOs * moved the transform_content_confirm calls for the layer buttons in AnimationTimeline (Add/remove/clone) to the project layer modification functions * animation first/last_frame tweaks and un-press play buttons when the first/last_frame are the same in _on_AnimationTimer_timeout in AnimationTimeline * Cleaned up project_changed in ANimationTimeline a bit * Cleaned up project_layer_added in AnimationTimeline * Changed Layer classes get_default_name to set_name_to_default * Cleaned up LayerButton.drop_data slightly * Looked at some of my TODOs * cleaned up copying cels * Fixed CelButton linked_indicator not showing up right away when becoming linked * Cleand up link/unlink cel menu option a little. Fixed situatoin where trying to call button_setup on cel_button that doesn't exist anymore due to undo/redo * Fixed regression with copy_cel (linked) in when cloning a frame * Minor cleanup, more detailed comments, updated TODOs * more improved comments * Made focus_mode on Cel/Layer/FrameButton NONE to fix bug where it looks like one is selected after pressing it and adding a new Layer/Frame (but its just in the focus state, not the pressed state * Made AnimationTimeline.change_layer_order work a little more consistantly with LayerButton.drop_data, and fixed a minor bug in it * Updated comments and TODOs * cleanup * removed some code that should no longer be needed * updated comment * removed Project's frames and layers setters _frames_changed and _layers_changed * Made some 'for x in range(array.size())' just 'for x in array.size()' * updated comments/TODOs * Cel content changes intial * Added 'content' methods to Cel classes * Removed image var from PixelCelButton * Reusing PixelCelButton.gd on GroupCelButton scene * Renamed PixelCelButton.gd to CelButton.gd (as it will be used for all Cel Buttons) and deleted GroupCelButton.gd * Hide the TransparentChecker on GroupCelButton.tscn until a preview texture is added for GroupCels * TODOs, prevent memory leak when closing projects * Link/unlink cel cleanup : * Added _project param to _init methods of Layer classes * Added update_texture method to Cel classes (moving part from the update_texture and update_selected_cels_textures methods from Canvas.gd * Removed a temporary check (which also fixed another bug) * Clone child layers when cloning a layer * Added temp dummy get_image method to GroupCel, and use get_image when copying or picking colors * TODOs * Made open_image_as_spritesheet_layer work after the timeline refactor (still doesn't work with groups yet though). TODO comment updates * Added create_new_cel methods to Layer classes * Updated TODOs and comments * Renamed Layer class's create_empty_cel to new_empty_cel to match Project's new_emtpy_frame * Renamed create_layer/cel_button to instantiate_layer/cel_button * updated TODOs * prioritized TODOs * Fixed some warnings * removed commented out code from previous commit * Fixed export * Made open_image_as_new_frame work after timeline refactor * Fixed open_image_as_new_layer after timeline refactor * Some linked cel fixes * More linked cels fixes * cleanup * Optimized importing spreadsheet as new layer * Fixed Scale Image crash with Groups * Fixed onion skin with groups * Removed blend_mode from BaseLayer for now * Mostly fixed image effects * Fixed resize canvas * Fixed drag and drop not working with Cel Buttons on Group Layers * updated TODOs * Renamed Replace Frame (in open image) to Replace Cel * Continued renaming Replace Frame to Replace Cel * Made open_image_at_cels work after timeline refactor * Added get_layer_path method to BaseLayer * Replaced AtLayerSpinbox with AtLayerOption for Open Image as New Frame or Replace Cel * Updated TODOs * updated TODOs * Comments for cel content methods * fixed right clicking group cel button deselecting the button (even though cel is still selected * frame/layer modification methods comments * Removed unneeded size flags * TODO updates * Removed a loop that would never run from open_image_as_spritesheet_tab * TODO update * Combined BaseLayer.get_children_direct and get_children_recursive into a single get_children method with a bool for recursive. Added a get_child_count method * Removed unneeded frame paramaters from _on_DeleteFrame_pressed and _on_CopyFrame_pressed * TODO Updates * Removed unneeded code from delete_frames * Made delete_frames variable names more consistent with my other changes * Continuation * made variable names in copy_frames more consistent with rest of changes * Update TODOs * Removed TODOs for after this PR (moved to my notes) * Fixed crash when pasting image on Group * Fixed layer .visible check to be is_visible_in_hierarchy() * Removed some drag highlight polish code that didn't work * Removed code from Canvas update_texture and update_selected_cels_textures that was redundant * gdformat * gdformat * gdlint fixes * Fixed Cel button not having its linked indicator show when enabling new cels linked on a layer other than the current layer * Fixed crop image and centralize image * Added '# gdlint: ignore=max-public-methods' to the top of Project' * Fixed dragging cels to layer of different type crash * Formatted CelButton.gd Co-authored-by: MrTriPie <MrTriPie>
This commit is contained in:
parent
5914471149
commit
1fa34d7196
|
@ -316,7 +316,7 @@ msgstr ""
|
|||
msgid "New frame"
|
||||
msgstr ""
|
||||
|
||||
msgid "Replace frame"
|
||||
msgid "Replace cel"
|
||||
msgstr ""
|
||||
|
||||
msgid "New layer"
|
||||
|
@ -1553,12 +1553,18 @@ msgstr ""
|
|||
msgid "Layer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Layers"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create a new layer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Create a new group layer"
|
||||
msgstr ""
|
||||
|
||||
msgid "Remove current layer"
|
||||
msgstr ""
|
||||
|
||||
|
@ -1593,6 +1599,9 @@ msgid "Enable/disable cel linking\n\n"
|
|||
"Linked cels are being shared across multiple frames"
|
||||
msgstr ""
|
||||
|
||||
msgid "Expand/collapse group"
|
||||
msgstr ""
|
||||
|
||||
msgid "Palette"
|
||||
msgstr ""
|
||||
|
||||
|
|
BIN
assets/graphics/layers/group_collapsed.png
Normal file
BIN
assets/graphics/layers/group_collapsed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 180 B |
35
assets/graphics/layers/group_collapsed.png.import
Normal file
35
assets/graphics/layers/group_collapsed.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/group_collapsed.png-9d08fac1c2f635c754860111d024aa0f.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/layers/group_collapsed.png"
|
||||
dest_files=[ "res://.import/group_collapsed.png-9d08fac1c2f635c754860111d024aa0f.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
BIN
assets/graphics/layers/group_expanded.png
Normal file
BIN
assets/graphics/layers/group_expanded.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 202 B |
35
assets/graphics/layers/group_expanded.png.import
Normal file
35
assets/graphics/layers/group_expanded.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/group_expanded.png-f3cd620185a4989737d6d9a36f4b57f3.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/layers/group_expanded.png"
|
||||
dest_files=[ "res://.import/group_expanded.png-f3cd620185a4989737d6d9a36f4b57f3.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
BIN
assets/graphics/layers/group_new.png
Normal file
BIN
assets/graphics/layers/group_new.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 184 B |
35
assets/graphics/layers/group_new.png.import
Normal file
35
assets/graphics/layers/group_new.png.import
Normal file
|
@ -0,0 +1,35 @@
|
|||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/group_new.png-4ebdc7dd84d8c8a7b7979f50f4471543.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/graphics/layers/group_new.png"
|
||||
dest_files=[ "res://.import/group_new.png-4ebdc7dd84d8c8a7b7979f50f4471543.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=false
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
process/normal_map_invert_y=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=false
|
||||
svg/scale=1.0
|
|
@ -14,6 +14,16 @@ _global_script_classes=[ {
|
|||
"language": "GDScript",
|
||||
"path": "res://src/Classes/AnimationTag.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "BaseCel",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/BaseCel.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "BaseLayer",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/BaseLayer.gd"
|
||||
}, {
|
||||
"base": "VBoxContainer",
|
||||
"class": "BaseTool",
|
||||
"language": "GDScript",
|
||||
|
@ -30,11 +40,6 @@ _global_script_classes=[ {
|
|||
"path": "res://src/UI/Canvas/Canvas.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "Cel",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/Cel.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "Drawer",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/Drawers.gd"
|
||||
|
@ -49,6 +54,16 @@ _global_script_classes=[ {
|
|||
"language": "GDScript",
|
||||
"path": "res://src/UI/Nodes/GradientEdit.gd"
|
||||
}, {
|
||||
"base": "BaseCel",
|
||||
"class": "GroupCel",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/GroupCel.gd"
|
||||
}, {
|
||||
"base": "BaseLayer",
|
||||
"class": "GroupLayer",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/GroupLayer.gd"
|
||||
}, {
|
||||
"base": "Line2D",
|
||||
"class": "Guide",
|
||||
"language": "GDScript",
|
||||
|
@ -59,11 +74,6 @@ _global_script_classes=[ {
|
|||
"language": "GDScript",
|
||||
"path": "res://src/Classes/ImageEffect.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "Layer",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/Layer.gd"
|
||||
}, {
|
||||
"base": "Button",
|
||||
"class": "LayerButton",
|
||||
"language": "GDScript",
|
||||
|
@ -99,6 +109,16 @@ _global_script_classes=[ {
|
|||
"language": "GDScript",
|
||||
"path": "res://src/UI/PatternsPopup.gd"
|
||||
}, {
|
||||
"base": "BaseCel",
|
||||
"class": "PixelCel",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/PixelCel.gd"
|
||||
}, {
|
||||
"base": "BaseLayer",
|
||||
"class": "PixelLayer",
|
||||
"language": "GDScript",
|
||||
"path": "res://src/Classes/PixelLayer.gd"
|
||||
}, {
|
||||
"base": "Reference",
|
||||
"class": "Project",
|
||||
"language": "GDScript",
|
||||
|
@ -136,16 +156,18 @@ _global_script_classes=[ {
|
|||
} ]
|
||||
_global_script_class_icons={
|
||||
"AnimationTag": "",
|
||||
"BaseCel": "",
|
||||
"BaseLayer": "",
|
||||
"BaseTool": "",
|
||||
"Brushes": "",
|
||||
"Canvas": "",
|
||||
"Cel": "",
|
||||
"Drawer": "",
|
||||
"Frame": "",
|
||||
"GradientEditNode": "",
|
||||
"GroupCel": "",
|
||||
"GroupLayer": "",
|
||||
"Guide": "",
|
||||
"ImageEffect": "",
|
||||
"Layer": "",
|
||||
"LayerButton": "",
|
||||
"Palette": "",
|
||||
"PaletteColor": "",
|
||||
|
@ -153,6 +175,8 @@ _global_script_class_icons={
|
|||
"PalettePanel": "",
|
||||
"PaletteSwatch": "",
|
||||
"Patterns": "",
|
||||
"PixelCel": "",
|
||||
"PixelLayer": "",
|
||||
"Project": "",
|
||||
"SelectionMap": "",
|
||||
"SelectionTool": "",
|
||||
|
|
|
@ -423,6 +423,8 @@ func scale_image(width: int, height: int, interpolation: int) -> void:
|
|||
|
||||
for f in Global.current_project.frames:
|
||||
for i in range(f.cels.size() - 1, -1, -1):
|
||||
if f.cels[i] is GroupCel:
|
||||
continue
|
||||
var sprite := Image.new()
|
||||
sprite.copy_from(f.cels[i].image)
|
||||
# Different method for scale_3x
|
||||
|
@ -449,6 +451,8 @@ func centralize() -> void:
|
|||
# Find used rect of the current frame (across all of the layers)
|
||||
var used_rect := Rect2()
|
||||
for cel in Global.current_project.frames[Global.current_project.current_frame].cels:
|
||||
if not cel is PixelCel:
|
||||
continue
|
||||
var cel_rect: Rect2 = cel.image.get_used_rect()
|
||||
if not cel_rect.has_no_area():
|
||||
used_rect = cel_rect if used_rect.has_no_area() else used_rect.merge(cel_rect)
|
||||
|
@ -457,14 +461,16 @@ func centralize() -> void:
|
|||
|
||||
var offset: Vector2 = (0.5 * (Global.current_project.size - used_rect.size)).floor()
|
||||
general_do_centralize()
|
||||
for c in Global.current_project.frames[Global.current_project.current_frame].cels:
|
||||
for cel in Global.current_project.frames[Global.current_project.current_frame].cels:
|
||||
if not cel is PixelCel:
|
||||
continue
|
||||
var sprite := Image.new()
|
||||
sprite.create(
|
||||
Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8
|
||||
)
|
||||
sprite.blend_rect(c.image, used_rect, offset)
|
||||
Global.current_project.undo_redo.add_do_property(c.image, "data", sprite.data)
|
||||
Global.current_project.undo_redo.add_undo_property(c.image, "data", c.image.data)
|
||||
sprite.blend_rect(cel.image, used_rect, offset)
|
||||
Global.current_project.undo_redo.add_do_property(cel.image, "data", sprite.data)
|
||||
Global.current_project.undo_redo.add_undo_property(cel.image, "data", cel.image.data)
|
||||
general_undo_centralize()
|
||||
|
||||
|
||||
|
@ -473,6 +479,8 @@ func crop_image() -> void:
|
|||
var used_rect := Rect2()
|
||||
for f in Global.current_project.frames:
|
||||
for cel in f.cels:
|
||||
if not cel is PixelCel:
|
||||
continue
|
||||
cel.image.unlock() # May be unneeded now, but keep it just in case
|
||||
var cel_used_rect: Rect2 = cel.image.get_used_rect()
|
||||
if cel_used_rect == Rect2(0, 0, 0, 0): # If the cel has no content
|
||||
|
@ -493,6 +501,8 @@ func crop_image() -> void:
|
|||
# Loop through all the cels to crop them
|
||||
for f in Global.current_project.frames:
|
||||
for cel in f.cels:
|
||||
if not cel is PixelCel:
|
||||
continue
|
||||
var sprite: Image = cel.image.get_rect(used_rect)
|
||||
Global.current_project.undo_redo.add_do_property(cel.image, "data", sprite.data)
|
||||
Global.current_project.undo_redo.add_undo_property(cel.image, "data", cel.image.data)
|
||||
|
@ -504,6 +514,8 @@ func resize_canvas(width: int, height: int, offset_x: int, offset_y: int) -> voi
|
|||
general_do_scale(width, height)
|
||||
for f in Global.current_project.frames:
|
||||
for c in f.cels:
|
||||
if not c is PixelCel:
|
||||
continue
|
||||
var sprite := Image.new()
|
||||
sprite.create(width, height, false, Image.FORMAT_RGBA8)
|
||||
sprite.blend_rect(
|
||||
|
|
|
@ -380,7 +380,7 @@ func blend_layers(image: Image, frame: Frame, origin: Vector2 = Vector2(0, 0)) -
|
|||
image.lock()
|
||||
var layer_i := 0
|
||||
for cel in frame.cels:
|
||||
if Global.current_project.layers[layer_i].visible:
|
||||
if Global.current_project.layers[layer_i].is_visible_in_hierarchy() and cel is PixelCel:
|
||||
var cel_image := Image.new()
|
||||
cel_image.copy_from(cel.image)
|
||||
cel_image.lock()
|
||||
|
@ -406,9 +406,12 @@ func blend_selected_cels(image: Image, frame: Frame, origin: Vector2 = Vector2(0
|
|||
var test_array = [Global.current_project.current_frame, cel_ind]
|
||||
if not test_array in Global.current_project.selected_cels:
|
||||
continue
|
||||
if not frame.cels[cel_ind] is PixelCel:
|
||||
continue
|
||||
|
||||
var cel: Cel = frame.cels[cel_ind]
|
||||
if Global.current_project.layers[layer_i].visible:
|
||||
var cel: PixelCel = frame.cels[cel_ind]
|
||||
|
||||
if Global.current_project.layers[layer_i].is_visible_in_hierarchy():
|
||||
var cel_image := Image.new()
|
||||
cel_image.copy_from(cel.image)
|
||||
cel_image.lock()
|
||||
|
|
|
@ -2,6 +2,7 @@ extends Node
|
|||
|
||||
signal project_changed
|
||||
|
||||
enum LayerTypes { PIXEL, GROUP }
|
||||
enum GridTypes { CARTESIAN, ISOMETRIC, ALL }
|
||||
enum PressureSensitivity { NONE, ALPHA, SIZE, ALPHA_AND_SIZE }
|
||||
enum ColorFrom { THEME, CUSTOM }
|
||||
|
@ -59,7 +60,6 @@ var current_project_index := 0 setget _project_changed
|
|||
var ui_tooltips := {}
|
||||
|
||||
# Canvas related stuff
|
||||
var layers_changed_skip := false
|
||||
var can_draw := false
|
||||
var move_guides_on_canvas := false
|
||||
var has_focus := false
|
||||
|
@ -144,6 +144,10 @@ var palettes := {}
|
|||
|
||||
# Nodes
|
||||
var notification_label_node: PackedScene = preload("res://src/UI/NotificationLabel.tscn")
|
||||
var pixel_layer_button_node: PackedScene = preload("res://src/UI/Timeline/PixelLayerButton.tscn")
|
||||
var group_layer_button_node: PackedScene = preload("res://src/UI/Timeline/GroupLayerButton.tscn")
|
||||
var pixel_cel_button_node: PackedScene = preload("res://src/UI/Timeline/PixelCelButton.tscn")
|
||||
var group_cel_button_node: PackedScene = preload("res://src/UI/Timeline/GroupCelButton.tscn")
|
||||
|
||||
onready var control: Node = get_tree().current_scene
|
||||
|
||||
|
@ -449,24 +453,14 @@ func undo_or_redo(
|
|||
if action_name == "Scale":
|
||||
for i in project.frames.size():
|
||||
for j in project.layers.size():
|
||||
var current_cel: Cel = project.frames[i].cels[j]
|
||||
current_cel.image_texture.create_from_image(current_cel.image, 0)
|
||||
var current_cel: BaseCel = project.frames[i].cels[j]
|
||||
current_cel.image_texture.create_from_image(current_cel.get_image(), 0)
|
||||
canvas.camera_zoom()
|
||||
canvas.grid.update()
|
||||
canvas.pixel_grid.update()
|
||||
project.selection_map_changed()
|
||||
cursor_position_label.text = "[%s×%s]" % [project.size.x, project.size.y]
|
||||
|
||||
elif "Frame" in action_name:
|
||||
# This actually means that frames.size is one, but it hasn't been updated yet
|
||||
if (undo and project.frames.size() == 2) or project.frames.size() == 1: # Stop animating
|
||||
play_forward.pressed = false
|
||||
play_backwards.pressed = false
|
||||
animation_timer.stop()
|
||||
|
||||
elif "Move Cels" == action_name:
|
||||
project.frames = project.frames # to call frames_changed
|
||||
|
||||
canvas.update()
|
||||
if !project.has_changed:
|
||||
project.has_changed = true
|
||||
|
|
|
@ -110,11 +110,7 @@ func open_pxo_file(path: String, untitled_backup: bool = false, replace_empty: b
|
|||
new_project.deserialize(dict.result)
|
||||
for frame in new_project.frames:
|
||||
for cel in frame.cels:
|
||||
var buffer := file.get_buffer(new_project.size.x * new_project.size.y * 4)
|
||||
cel.image.create_from_data(
|
||||
new_project.size.x, new_project.size.y, false, Image.FORMAT_RGBA8, buffer
|
||||
)
|
||||
cel.image = cel.image # Just to call image_changed
|
||||
cel.load_image_data_from_pxo(file, new_project.size)
|
||||
|
||||
if dict.result.has("brushes"):
|
||||
for brush in dict.result.brushes:
|
||||
|
@ -138,14 +134,13 @@ func open_pxo_file(path: String, untitled_backup: bool = false, replace_empty: b
|
|||
new_project.tiles.reset_mask()
|
||||
|
||||
file.close()
|
||||
if !empty_project:
|
||||
Global.projects.append(new_project)
|
||||
Global.tabs.current_tab = Global.tabs.get_tab_count() - 1
|
||||
else:
|
||||
if empty_project:
|
||||
if dict.error == OK and dict.result.has("fps"):
|
||||
Global.animation_timeline.fps_spinbox.value = dict.result.fps
|
||||
new_project.frames = new_project.frames # Just to call frames_changed
|
||||
new_project.layers = new_project.layers # Just to call layers_changed
|
||||
Global.animation_timeline.project_changed()
|
||||
else:
|
||||
Global.projects.append(new_project)
|
||||
Global.tabs.current_tab = Global.tabs.get_tab_count() - 1
|
||||
Global.canvas.camera_zoom()
|
||||
|
||||
if not untitled_backup:
|
||||
|
@ -200,13 +195,16 @@ func open_old_pxo_file(file: File, new_project: Project, first_line: String) ->
|
|||
if file_major_version >= 0 and file_minor_version > 6:
|
||||
var global_layer_line := file.get_line()
|
||||
while global_layer_line == ".":
|
||||
var layer_name := file.get_line()
|
||||
var layer_visibility := file.get_8()
|
||||
var layer_lock := file.get_8()
|
||||
var layer_new_cels_linked := file.get_8()
|
||||
var layer_dict := {
|
||||
"name": file.get_line(),
|
||||
"visible": file.get_8(),
|
||||
"locked": file.get_8(),
|
||||
"new_cels_linked": file.get_8(),
|
||||
"linked_cels": []
|
||||
}
|
||||
linked_cels.append(file.get_var())
|
||||
|
||||
var l := Layer.new(layer_name, layer_visibility, layer_lock, layer_new_cels_linked, [])
|
||||
var l := PixelLayer.new(new_project)
|
||||
l.deserialize(layer_dict)
|
||||
new_project.layers.append(l)
|
||||
global_layer_line = file.get_line()
|
||||
|
||||
|
@ -223,17 +221,17 @@ func open_old_pxo_file(file: File, new_project: Project, first_line: String) ->
|
|||
if file_major_version == 0 and file_minor_version < 7:
|
||||
var layer_name_old_version = file.get_line()
|
||||
if frame == 0:
|
||||
var l := Layer.new(layer_name_old_version)
|
||||
var l := PixelLayer.new(new_project, layer_name_old_version)
|
||||
new_project.layers.append(l)
|
||||
var cel_opacity := 1.0
|
||||
if file_major_version >= 0 and file_minor_version > 5:
|
||||
cel_opacity = file.get_float()
|
||||
var image := Image.new()
|
||||
image.create_from_data(width, height, false, Image.FORMAT_RGBA8, buffer)
|
||||
frame_class.cels.append(Cel.new(image, cel_opacity))
|
||||
frame_class.cels.append(PixelCel.new(image, cel_opacity))
|
||||
if file_major_version >= 0 and file_minor_version >= 7:
|
||||
if frame in linked_cels[layer_i]:
|
||||
var linked_cel: Cel = new_project.layers[layer_i].linked_cels[0].cels[layer_i]
|
||||
var linked_cel: PixelCel = new_project.layers[layer_i].linked_cels[0].cels[layer_i]
|
||||
new_project.layers[layer_i].linked_cels.append(frame_class)
|
||||
frame_class.cels[layer_i].image = linked_cel.image
|
||||
frame_class.cels[layer_i].image_texture = linked_cel.image_texture
|
||||
|
@ -358,7 +356,7 @@ func save_pxo_file(
|
|||
file.store_line(to_save)
|
||||
for frame in project.frames:
|
||||
for cel in frame.cels:
|
||||
file.store_buffer(cel.image.get_data())
|
||||
cel.save_image_data_to_pxo(file)
|
||||
|
||||
for brush in project.brushes:
|
||||
file.store_buffer(brush.get_data())
|
||||
|
@ -401,12 +399,12 @@ func save_pxo_file(
|
|||
|
||||
func open_image_as_new_tab(path: String, image: Image) -> void:
|
||||
var project = Project.new([], path.get_file(), image.get_size())
|
||||
project.layers.append(Layer.new())
|
||||
project.layers.append(PixelLayer.new(project))
|
||||
Global.projects.append(project)
|
||||
|
||||
var frame := Frame.new()
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
frame.cels.append(Cel.new(image, 1))
|
||||
frame.cels.append(PixelCel.new(image, 1))
|
||||
|
||||
project.frames.append(frame)
|
||||
set_new_imported_tab(project, path)
|
||||
|
@ -414,7 +412,7 @@ func open_image_as_new_tab(path: String, image: Image) -> void:
|
|||
|
||||
func open_image_as_spritesheet_tab(path: String, image: Image, horiz: int, vert: int) -> void:
|
||||
var project = Project.new([], path.get_file())
|
||||
project.layers.append(Layer.new())
|
||||
project.layers.append(PixelLayer.new(project))
|
||||
Global.projects.append(project)
|
||||
horiz = min(horiz, image.get_size().x)
|
||||
vert = min(vert, image.get_size().y)
|
||||
|
@ -429,16 +427,8 @@ func open_image_as_spritesheet_tab(path: String, image: Image, horiz: int, vert:
|
|||
)
|
||||
project.size = cropped_image.get_size()
|
||||
cropped_image.convert(Image.FORMAT_RGBA8)
|
||||
frame.cels.append(Cel.new(cropped_image, 1))
|
||||
|
||||
for _i in range(1, project.layers.size()):
|
||||
var empty_sprite := Image.new()
|
||||
empty_sprite.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
|
||||
empty_sprite.fill(Color(0, 0, 0, 0))
|
||||
frame.cels.append(Cel.new(empty_sprite, 1))
|
||||
|
||||
frame.cels.append(PixelCel.new(cropped_image, 1))
|
||||
project.frames.append(frame)
|
||||
|
||||
set_new_imported_tab(project, path)
|
||||
|
||||
|
||||
|
@ -461,95 +451,84 @@ func open_image_as_spritesheet_layer(
|
|||
# Initialize undo mechanism
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Add Spritesheet Layer")
|
||||
var new_layers: Array = project.layers.duplicate()
|
||||
var new_frames: Array = []
|
||||
# Create a duplicate of "project.frames"
|
||||
for i in project.frames.size():
|
||||
var frame := Frame.new()
|
||||
frame.cels = project.frames[i].cels.duplicate(true)
|
||||
new_frames.append(frame)
|
||||
var new_layers: Array = project.layers.duplicate() # Used for updating linked_cels lists
|
||||
|
||||
# Create new frames (if needed)
|
||||
var new_frames_size = start_frame + (vertical * horizontal)
|
||||
var new_frames_size = max(project.frames.size(), start_frame + (vertical * horizontal))
|
||||
var frames := []
|
||||
var frame_indices: Array
|
||||
if new_frames_size > project.frames.size():
|
||||
var required_frames = new_frames_size - project.frames.size()
|
||||
frame_indices = range(
|
||||
project.current_frame + 1, project.current_frame + required_frames + 1
|
||||
)
|
||||
for i in required_frames:
|
||||
var new_frame := Frame.new()
|
||||
for l_i in range(new_layers.size()): # Create as many cels as there are layers
|
||||
var new_img := Image.new()
|
||||
new_img.create(project_width, project_height, false, Image.FORMAT_RGBA8)
|
||||
new_frame.cels.append(Cel.new(new_img, 1))
|
||||
if new_layers[l_i].new_cels_linked:
|
||||
for l_i in range(project.layers.size()): # Create as many cels as there are layers
|
||||
new_frame.cels.append(project.layers[l_i].new_empty_cel())
|
||||
if new_layers[l_i].get("new_cels_linked"):
|
||||
new_layers[l_i].linked_cels.append(new_frame)
|
||||
new_frame.cels[l_i].image = new_layers[l_i].linked_cels[0].cels[l_i].image
|
||||
new_frame.cels[l_i].set_content(
|
||||
new_layers[l_i].linked_cels[0].cels[l_i].get_content()
|
||||
)
|
||||
new_frame.cels[l_i].image_texture = new_layers[l_i].linked_cels[0].cels[l_i].image_texture
|
||||
new_frames.insert(project.current_frame + 1, new_frame)
|
||||
frames.append(new_frame)
|
||||
|
||||
# Create new layer for spritesheet
|
||||
var layer := Layer.new(file_name)
|
||||
new_layers.append(layer)
|
||||
for f in new_frames:
|
||||
var new_layer := Image.new()
|
||||
new_layer.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
|
||||
f.cels.append(Cel.new(new_layer, 1))
|
||||
|
||||
# Slice spritesheet
|
||||
var image_no: int = 0
|
||||
var layer_index = new_layers.size() - 1
|
||||
for yy in range(vertical):
|
||||
for xx in range(horizontal):
|
||||
var layer := PixelLayer.new(project, file_name)
|
||||
var cels := []
|
||||
for f in new_frames_size:
|
||||
if f >= start_frame and f < (start_frame + (vertical * horizontal)):
|
||||
# Slice spritesheet
|
||||
var xx: int = (f - start_frame) % horizontal
|
||||
var yy: int = (f - start_frame) / horizontal
|
||||
var cropped_image := Image.new()
|
||||
cropped_image = image.get_rect(
|
||||
Rect2(frame_width * xx, frame_height * yy, frame_width, frame_height)
|
||||
)
|
||||
cropped_image.crop(project.size.x, project.size.y)
|
||||
var frame_index = start_frame + image_no
|
||||
|
||||
cropped_image.convert(Image.FORMAT_RGBA8)
|
||||
new_frames[frame_index].cels[layer_index] = (Cel.new(cropped_image, 1))
|
||||
image_no += 1
|
||||
cels.append(PixelCel.new(cropped_image))
|
||||
else:
|
||||
cels.append(layer.new_empty_cel())
|
||||
|
||||
project.undo_redo.add_do_property(project, "current_frame", new_frames.size() - 1)
|
||||
project.undo_redo.add_do_property(project, "current_frame", new_frames_size - 1)
|
||||
project.undo_redo.add_do_property(project, "current_layer", project.layers.size())
|
||||
project.undo_redo.add_do_property(project, "frames", new_frames)
|
||||
project.undo_redo.add_do_method(project, "add_frames", frames, frame_indices)
|
||||
project.undo_redo.add_do_property(project, "layers", new_layers)
|
||||
project.undo_redo.add_do_method(project, "add_layers", [layer], [project.layers.size()], [cels])
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_method(project, "remove_layers", [project.layers.size()])
|
||||
project.undo_redo.add_undo_property(project, "layers", project.layers)
|
||||
project.undo_redo.add_undo_property(project, "frames", project.frames)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(project, "remove_frames", frame_indices)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func open_image_at_frame(image: Image, layer_index := 0, frame_index := 0) -> void:
|
||||
func open_image_at_cel(image: Image, layer_index := 0, frame_index := 0) -> void:
|
||||
var project = Global.current_project
|
||||
image.crop(project.size.x, project.size.y)
|
||||
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Replaced Frame")
|
||||
|
||||
var frames: Array = []
|
||||
# create a duplicate of "project.frames"
|
||||
for i in project.frames.size():
|
||||
var frame := Frame.new()
|
||||
frame.cels = project.frames[i].cels.duplicate(true)
|
||||
frames.append(frame)
|
||||
project.undo_redo.create_action("Replaced Cel")
|
||||
|
||||
for i in project.frames.size():
|
||||
if i == frame_index:
|
||||
image.crop(project.size.x, project.size.y)
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
frames[i].cels[layer_index] = (Cel.new(image, 1))
|
||||
project.undo_redo.add_do_property(project.frames[i], "cels", frames[i].cels)
|
||||
project.undo_redo.add_undo_property(project.frames[i], "cels", project.frames[i].cels)
|
||||
var cel: PixelCel = project.frames[i].cels[layer_index]
|
||||
project.undo_redo.add_do_property(cel, "image", image)
|
||||
project.undo_redo.add_undo_property(cel, "image", cel.image)
|
||||
|
||||
project.undo_redo.add_do_property(project, "frames", frames)
|
||||
project.undo_redo.add_do_property(project, "selected_cels", [])
|
||||
project.undo_redo.add_do_property(project, "current_layer", layer_index)
|
||||
project.undo_redo.add_do_property(project, "current_frame", frame_index)
|
||||
|
||||
project.undo_redo.add_undo_property(project, "frames", project.frames)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
|
||||
project.undo_redo.add_undo_property(project, "selected_cels", [])
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
@ -557,64 +536,50 @@ func open_image_at_frame(image: Image, layer_index := 0, frame_index := 0) -> vo
|
|||
func open_image_as_new_frame(image: Image, layer_index := 0) -> void:
|
||||
var project = Global.current_project
|
||||
image.crop(project.size.x, project.size.y)
|
||||
var new_frames: Array = project.frames.duplicate()
|
||||
|
||||
var frame := Frame.new()
|
||||
for i in project.layers.size():
|
||||
if i == layer_index:
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
frame.cels.append(Cel.new(image, 1))
|
||||
frame.cels.append(PixelCel.new(image, 1))
|
||||
else:
|
||||
var empty_image := Image.new()
|
||||
empty_image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
|
||||
frame.cels.append(Cel.new(empty_image, 1))
|
||||
|
||||
new_frames.append(frame)
|
||||
frame.cels.append(project.layers[i].new_empty_cel())
|
||||
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Add Frame")
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
|
||||
project.undo_redo.add_do_property(project, "frames", new_frames)
|
||||
project.undo_redo.add_do_property(project, "current_frame", new_frames.size() - 1)
|
||||
project.undo_redo.add_do_method(project, "add_frames", [frame], [project.frames.size()])
|
||||
project.undo_redo.add_do_property(project, "current_layer", layer_index)
|
||||
project.undo_redo.add_do_property(project, "current_frame", project.frames.size())
|
||||
|
||||
project.undo_redo.add_undo_property(project, "frames", project.frames)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_undo_method(project, "remove_frames", [project.frames.size()])
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func open_image_as_new_layer(image: Image, file_name: String, frame_index := 0) -> void:
|
||||
var project = Global.current_project
|
||||
image.crop(project.size.x, project.size.y)
|
||||
var new_layers: Array = Global.current_project.layers.duplicate()
|
||||
var layer := Layer.new(file_name)
|
||||
var layer := PixelLayer.new(project, file_name)
|
||||
var cels := []
|
||||
|
||||
Global.current_project.undos += 1
|
||||
Global.current_project.undo_redo.create_action("Add Layer")
|
||||
for i in project.frames.size():
|
||||
var new_cels: Array = project.frames[i].cels.duplicate(true)
|
||||
if i == frame_index:
|
||||
image.convert(Image.FORMAT_RGBA8)
|
||||
new_cels.append(Cel.new(image, 1))
|
||||
cels.append(PixelCel.new(image, 1))
|
||||
else:
|
||||
var empty_image := Image.new()
|
||||
empty_image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
|
||||
new_cels.append(Cel.new(empty_image, 1))
|
||||
cels.append(layer.new_empty_cel())
|
||||
|
||||
project.undo_redo.add_do_property(project.frames[i], "cels", new_cels)
|
||||
project.undo_redo.add_undo_property(project.frames[i], "cels", project.frames[i].cels)
|
||||
|
||||
new_layers.append(layer)
|
||||
|
||||
project.undo_redo.add_do_property(project, "current_layer", new_layers.size() - 1)
|
||||
project.undo_redo.add_do_property(project, "layers", new_layers)
|
||||
project.undo_redo.add_do_property(project, "current_layer", project.layers.size())
|
||||
project.undo_redo.add_do_method(project, "add_layers", [layer], [project.layers.size()], [cels])
|
||||
project.undo_redo.add_do_property(project, "current_frame", frame_index)
|
||||
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_undo_property(project, "layers", project.layers)
|
||||
project.undo_redo.add_undo_method(project, "remove_layers", [project.layers.size()])
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
|
|
|
@ -174,7 +174,7 @@ func _fill_new_palette_with_colors(
|
|||
match get_colors_from:
|
||||
GetColorsFrom.CURRENT_CEL:
|
||||
for cel_index in current_project.selected_cels:
|
||||
var cel: Cel = current_project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
var cel: PixelCel = current_project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
cels.append(cel)
|
||||
GetColorsFrom.CURRENT_FRAME:
|
||||
for cel in current_project.frames[current_project.current_frame].cels:
|
||||
|
|
53
src/Classes/BaseCel.gd
Normal file
53
src/Classes/BaseCel.gd
Normal file
|
@ -0,0 +1,53 @@
|
|||
class_name BaseCel
|
||||
extends Reference
|
||||
# Base class for cel properties.
|
||||
# The term "cel" comes from "celluloid" (https://en.wikipedia.org/wiki/Cel).
|
||||
|
||||
var opacity: float
|
||||
var image_texture: ImageTexture
|
||||
|
||||
# Methods to Override:
|
||||
|
||||
|
||||
# The content methods deal with the unique content of each cel type. For example, an Image for
|
||||
# PixelLayers, or a Dictionary of settings for a procedural layer type, and null for Groups.
|
||||
# Can be used fo linking/unlinking cels, copying, and deleting content
|
||||
func get_content():
|
||||
return null
|
||||
|
||||
|
||||
func set_content(_content) -> void:
|
||||
return
|
||||
|
||||
|
||||
# Can be used to delete the content of the cel with set_content
|
||||
# (using the old content from get_content as undo data)
|
||||
func create_empty_content():
|
||||
return []
|
||||
|
||||
|
||||
# Can be used for creating copy content for copying cels or unlinking cels
|
||||
func copy_content():
|
||||
return []
|
||||
|
||||
|
||||
# Returns the image var for image based cel types, or a render for procedural types.
|
||||
# It's meant for read-only usage of image data, such as copying selections or color picking.
|
||||
func get_image() -> Image:
|
||||
return null
|
||||
|
||||
|
||||
func update_texture() -> void:
|
||||
return
|
||||
|
||||
|
||||
func save_image_data_to_pxo(_file: File) -> void:
|
||||
return
|
||||
|
||||
|
||||
func load_image_data_from_pxo(_file: File, _project_size: Vector2) -> void:
|
||||
return
|
||||
|
||||
|
||||
func instantiate_cel_button() -> Node:
|
||||
return null
|
139
src/Classes/BaseLayer.gd
Normal file
139
src/Classes/BaseLayer.gd
Normal file
|
@ -0,0 +1,139 @@
|
|||
class_name BaseLayer
|
||||
extends Reference
|
||||
# Base class for layer properties. Different layer types extend from this class.
|
||||
|
||||
var name := ""
|
||||
var visible := true
|
||||
var locked := false
|
||||
var parent: BaseLayer
|
||||
var project
|
||||
var index: int
|
||||
|
||||
|
||||
# Returns true if this is a direct or indirect parent of layer
|
||||
func is_a_parent_of(layer: BaseLayer) -> bool:
|
||||
if layer.parent == self:
|
||||
return true
|
||||
elif is_instance_valid(layer.parent):
|
||||
return is_a_parent_of(layer.parent)
|
||||
return false
|
||||
|
||||
|
||||
func get_children(recursive: bool) -> Array:
|
||||
var children := []
|
||||
if recursive:
|
||||
for i in index:
|
||||
if is_a_parent_of(project.layers[i]):
|
||||
children.append(project.layers[i])
|
||||
else:
|
||||
for i in index:
|
||||
if project.layers[i].parent == self:
|
||||
children.append(project.layers[i])
|
||||
return children
|
||||
|
||||
|
||||
func get_child_count(recursive: bool) -> int:
|
||||
var count := 0
|
||||
if recursive:
|
||||
for i in index:
|
||||
if is_a_parent_of(project.layers[i]):
|
||||
count += 1
|
||||
else:
|
||||
for i in index:
|
||||
if project.layers[i].parent == self:
|
||||
count += 1
|
||||
return count
|
||||
|
||||
|
||||
func has_children() -> bool:
|
||||
if index == 0:
|
||||
return false
|
||||
return project.layers[index - 1].parent == self
|
||||
|
||||
|
||||
func is_expanded_in_hierarchy() -> bool:
|
||||
if is_instance_valid(parent):
|
||||
return parent.expanded and parent.is_expanded_in_hierarchy()
|
||||
return true
|
||||
|
||||
|
||||
func is_visible_in_hierarchy() -> bool:
|
||||
if is_instance_valid(parent) and visible:
|
||||
return parent.is_visible_in_hierarchy()
|
||||
return visible
|
||||
|
||||
|
||||
func is_locked_in_hierarchy() -> bool:
|
||||
if is_instance_valid(parent) and not locked:
|
||||
return parent.is_locked_in_hierarchy()
|
||||
return locked
|
||||
|
||||
|
||||
func get_hierarchy_depth() -> int:
|
||||
if is_instance_valid(parent):
|
||||
return parent.get_hierarchy_depth() + 1
|
||||
return 0
|
||||
|
||||
|
||||
func get_layer_path() -> String:
|
||||
if is_instance_valid(parent):
|
||||
return str(parent.get_layer_path(), "/", name)
|
||||
return name
|
||||
|
||||
|
||||
# Methods to Override:
|
||||
|
||||
|
||||
func serialize() -> Dictionary:
|
||||
assert(index == project.layers.find(self))
|
||||
return {
|
||||
"name": name,
|
||||
"visible": visible,
|
||||
"locked": locked,
|
||||
"parent": parent.index if is_instance_valid(parent) else -1
|
||||
}
|
||||
|
||||
|
||||
func deserialize(dict: Dictionary) -> void:
|
||||
name = dict.name
|
||||
visible = dict.visible
|
||||
locked = dict.locked
|
||||
if dict.get("parent", -1) != -1:
|
||||
parent = project.layers[dict.parent]
|
||||
|
||||
|
||||
func copy() -> BaseLayer:
|
||||
var copy = get_script().new(project)
|
||||
copy.project = project
|
||||
copy.index = index
|
||||
copy.deserialize(serialize())
|
||||
return copy
|
||||
|
||||
|
||||
func new_empty_cel() -> BaseCel:
|
||||
return null
|
||||
|
||||
|
||||
func copy_cel(_frame: int, _linked: bool) -> BaseCel:
|
||||
return null
|
||||
|
||||
|
||||
# Used to copy all cels with cel linking properly set up between this set of copies:
|
||||
func copy_all_cels() -> Array:
|
||||
return []
|
||||
|
||||
|
||||
func set_name_to_default(number: int) -> void:
|
||||
name = tr("Layer") + " %s" % number
|
||||
|
||||
|
||||
func can_layer_get_drawn() -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func accepts_child(_layer: BaseLayer) -> bool:
|
||||
return false
|
||||
|
||||
|
||||
func instantiate_layer_button() -> Node:
|
||||
return null
|
|
@ -1,24 +0,0 @@
|
|||
class_name Cel
|
||||
extends Reference
|
||||
# A class for cel properties.
|
||||
# The term "cel" comes from "celluloid" (https://en.wikipedia.org/wiki/Cel).
|
||||
# The "image" variable is where the image data of each cel are.
|
||||
|
||||
var image: Image setget image_changed
|
||||
var image_texture: ImageTexture
|
||||
var opacity: float
|
||||
|
||||
|
||||
func _init(_image := Image.new(), _opacity := 1.0, _image_texture: ImageTexture = null) -> void:
|
||||
if _image_texture:
|
||||
image_texture = _image_texture
|
||||
else:
|
||||
image_texture = ImageTexture.new()
|
||||
self.image = _image
|
||||
opacity = _opacity
|
||||
|
||||
|
||||
func image_changed(value: Image) -> void:
|
||||
image = value
|
||||
if !image.is_empty():
|
||||
image_texture.create_from_image(image, 0)
|
21
src/Classes/GroupCel.gd
Normal file
21
src/Classes/GroupCel.gd
Normal file
|
@ -0,0 +1,21 @@
|
|||
class_name GroupCel
|
||||
extends BaseCel
|
||||
# A class for the properties of cels in GroupLayers.
|
||||
# The term "cel" comes from "celluloid" (https://en.wikipedia.org/wiki/Cel).
|
||||
|
||||
|
||||
func _init(_opacity := 1.0) -> void:
|
||||
opacity = _opacity
|
||||
image_texture = ImageTexture.new()
|
||||
|
||||
|
||||
func get_image() -> Image:
|
||||
var image = Image.new()
|
||||
image.create(
|
||||
Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8
|
||||
)
|
||||
return image
|
||||
|
||||
|
||||
func instantiate_cel_button() -> Node:
|
||||
return Global.group_cel_button_node.instance()
|
54
src/Classes/GroupLayer.gd
Normal file
54
src/Classes/GroupLayer.gd
Normal file
|
@ -0,0 +1,54 @@
|
|||
class_name GroupLayer
|
||||
extends BaseLayer
|
||||
# A class for group layer properties
|
||||
|
||||
var expanded := true
|
||||
|
||||
|
||||
func _init(_project, _name := "") -> void:
|
||||
project = _project
|
||||
name = _name
|
||||
|
||||
|
||||
# Overridden Methods:
|
||||
|
||||
|
||||
func serialize() -> Dictionary:
|
||||
var data = .serialize()
|
||||
data["type"] = Global.LayerTypes.GROUP
|
||||
data["expanded"] = expanded
|
||||
return data
|
||||
|
||||
|
||||
func deserialize(dict: Dictionary) -> void:
|
||||
.deserialize(dict)
|
||||
expanded = dict.expanded
|
||||
|
||||
|
||||
func new_empty_cel() -> BaseCel:
|
||||
return GroupCel.new()
|
||||
|
||||
|
||||
func copy_cel(frame_index: int, _linked: bool) -> BaseCel:
|
||||
var cel: GroupCel = project.frames[frame_index].cels[index]
|
||||
return GroupCel.new(cel.opacity)
|
||||
|
||||
|
||||
func copy_all_cels() -> Array:
|
||||
var cels := []
|
||||
for frame in project.frames:
|
||||
var cel: GroupCel = frame.cels[index]
|
||||
cels.append(GroupCel.new(cel.opacity))
|
||||
return cels
|
||||
|
||||
|
||||
func set_name_to_default(number: int) -> void:
|
||||
name = tr("Group") + " %s" % number
|
||||
|
||||
|
||||
func accepts_child(_layer: BaseLayer) -> bool:
|
||||
return true
|
||||
|
||||
|
||||
func instantiate_layer_button() -> Node:
|
||||
return Global.group_layer_button_node.instance()
|
|
@ -55,7 +55,7 @@ func _confirmed() -> void:
|
|||
for cel_index in project.selected_cels:
|
||||
if !project.layers[cel_index[1]].can_layer_get_drawn():
|
||||
continue
|
||||
var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
var cel: PixelCel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
var cel_image: Image = cel.image
|
||||
commit_action(cel_image)
|
||||
_commit_undo("Draw", undo_data, project)
|
||||
|
@ -126,12 +126,14 @@ func _get_selected_draw_images(project: Project) -> Array: # Array of Images
|
|||
var images := []
|
||||
if affect == SELECTED_CELS:
|
||||
for cel_index in project.selected_cels:
|
||||
var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
images.append(cel.image)
|
||||
var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
if cel is PixelCel:
|
||||
images.append(cel.image)
|
||||
else:
|
||||
for frame in project.frames:
|
||||
for cel in frame.cels:
|
||||
images.append(cel.image)
|
||||
if cel is PixelCel:
|
||||
images.append(cel.image)
|
||||
return images
|
||||
|
||||
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
class_name Layer
|
||||
extends Reference
|
||||
# A class for layer properties.
|
||||
|
||||
var name := ""
|
||||
var visible := true
|
||||
var locked := false
|
||||
var new_cels_linked := false
|
||||
var linked_cels := [] # Array of Frames
|
||||
|
||||
|
||||
func _init(
|
||||
_name := "", _visible := true, _locked := false, _new_cels_linked := false, _linked_cels := []
|
||||
) -> void:
|
||||
name = _name
|
||||
visible = _visible
|
||||
locked = _locked
|
||||
new_cels_linked = _new_cels_linked
|
||||
linked_cels = _linked_cels
|
||||
|
||||
|
||||
func can_layer_get_drawn() -> bool:
|
||||
return visible && !locked
|
69
src/Classes/PixelCel.gd
Normal file
69
src/Classes/PixelCel.gd
Normal file
|
@ -0,0 +1,69 @@
|
|||
class_name PixelCel
|
||||
extends BaseCel
|
||||
# A class for the properties of cels in PixelLayers.
|
||||
# The term "cel" comes from "celluloid" (https://en.wikipedia.org/wiki/Cel).
|
||||
# The "image" variable is where the image data of each cel are.
|
||||
|
||||
var image: Image setget image_changed
|
||||
|
||||
|
||||
func _init(_image := Image.new(), _opacity := 1.0, _image_texture: ImageTexture = null) -> void:
|
||||
if _image_texture:
|
||||
image_texture = _image_texture
|
||||
else:
|
||||
image_texture = ImageTexture.new()
|
||||
self.image = _image # Set image and call setter
|
||||
opacity = _opacity
|
||||
|
||||
|
||||
func image_changed(value: Image) -> void:
|
||||
image = value
|
||||
if !image.is_empty():
|
||||
image_texture.create_from_image(image, 0)
|
||||
|
||||
|
||||
func get_content():
|
||||
return image
|
||||
|
||||
|
||||
func set_content(content) -> void:
|
||||
image = content
|
||||
image_texture.create_from_image(image, 0)
|
||||
|
||||
|
||||
func create_empty_content():
|
||||
var empty_image := Image.new()
|
||||
empty_image.create(image.get_size().x, image.get_size().y, false, Image.FORMAT_RGBA8)
|
||||
return empty_image
|
||||
|
||||
|
||||
func copy_content():
|
||||
var copy_image := Image.new()
|
||||
copy_image.create_from_data(
|
||||
image.get_width(), image.get_height(), false, Image.FORMAT_RGBA8, image.get_data()
|
||||
)
|
||||
return copy_image
|
||||
|
||||
|
||||
func get_image() -> Image:
|
||||
return image
|
||||
|
||||
|
||||
func update_texture() -> void:
|
||||
image_texture.set_data(image)
|
||||
|
||||
|
||||
func save_image_data_to_pxo(file: File) -> void:
|
||||
file.store_buffer(image.get_data())
|
||||
|
||||
|
||||
func load_image_data_from_pxo(file: File, project_size: Vector2) -> void:
|
||||
var buffer := file.get_buffer(project_size.x * project_size.y * 4)
|
||||
image.create_from_data(project_size.x, project_size.y, false, Image.FORMAT_RGBA8, buffer)
|
||||
image_changed(image)
|
||||
|
||||
|
||||
func instantiate_cel_button() -> Node:
|
||||
var cel_button = Global.pixel_cel_button_node.instance()
|
||||
cel_button.get_child(0).texture = image_texture
|
||||
return cel_button
|
82
src/Classes/PixelLayer.gd
Normal file
82
src/Classes/PixelLayer.gd
Normal file
|
@ -0,0 +1,82 @@
|
|||
class_name PixelLayer
|
||||
extends BaseLayer
|
||||
# A class for standard pixel layer properties.
|
||||
|
||||
var new_cels_linked := false
|
||||
var linked_cels := [] # Array of Frames
|
||||
|
||||
|
||||
func _init(_project, _name := "") -> void:
|
||||
project = _project
|
||||
name = _name
|
||||
|
||||
|
||||
# Overridden Methods:
|
||||
|
||||
|
||||
func serialize() -> Dictionary:
|
||||
var dict = .serialize()
|
||||
dict["type"] = Global.LayerTypes.PIXEL
|
||||
dict["new_cels_linked"] = new_cels_linked
|
||||
dict["linked_cels"] = []
|
||||
for cel in linked_cels:
|
||||
dict.linked_cels.append(project.frames.find(cel))
|
||||
return dict
|
||||
|
||||
|
||||
func deserialize(dict: Dictionary) -> void:
|
||||
.deserialize(dict)
|
||||
new_cels_linked = dict.new_cels_linked
|
||||
|
||||
for linked_cel_number in dict.linked_cels:
|
||||
linked_cels.append(project.frames[linked_cel_number])
|
||||
var linked_cel: PixelCel = project.frames[linked_cel_number].cels[index]
|
||||
linked_cel.image = linked_cels[0].cels[index].image
|
||||
linked_cel.image_texture = linked_cels[0].cels[index].image_texture
|
||||
|
||||
|
||||
func new_empty_cel() -> BaseCel:
|
||||
var image := Image.new()
|
||||
image.create(project.size.x, project.size.y, false, Image.FORMAT_RGBA8)
|
||||
return PixelCel.new(image)
|
||||
|
||||
|
||||
func copy_cel(frame_index: int, linked: bool) -> BaseCel:
|
||||
if linked and not linked_cels.empty():
|
||||
var cel: PixelCel = linked_cels[0].cels[index]
|
||||
return PixelCel.new(cel.image, cel.opacity, cel.image_texture)
|
||||
else:
|
||||
var cel: PixelCel = project.frames[frame_index].cels[index]
|
||||
var copy_image := Image.new()
|
||||
copy_image.copy_from(cel.image)
|
||||
return PixelCel.new(copy_image, cel.opacity)
|
||||
|
||||
|
||||
func copy_all_cels() -> Array:
|
||||
var cels := []
|
||||
|
||||
var linked_image: Image
|
||||
var linked_texture: ImageTexture
|
||||
if not linked_cels.empty():
|
||||
var cel: PixelCel = linked_cels[0].cels[index]
|
||||
linked_image = Image.new()
|
||||
linked_image.copy_from(cel.image)
|
||||
linked_texture = ImageTexture.new()
|
||||
|
||||
for frame in project.frames:
|
||||
var cel: PixelCel = frame.cels[index]
|
||||
if linked_cels.has(frame):
|
||||
cels.append(PixelCel.new(linked_image, cel.opacity, linked_texture))
|
||||
else:
|
||||
var copy_image := Image.new()
|
||||
copy_image.copy_from(cel.image)
|
||||
cels.append(PixelCel.new(copy_image, cel.opacity))
|
||||
return cels
|
||||
|
||||
|
||||
func can_layer_get_drawn() -> bool:
|
||||
return is_visible_in_hierarchy() && !is_locked_in_hierarchy()
|
||||
|
||||
|
||||
func instantiate_layer_button() -> Node:
|
||||
return Global.pixel_layer_button_node.instance()
|
|
@ -1,3 +1,4 @@
|
|||
# gdlint: ignore=max-public-methods
|
||||
class_name Project
|
||||
extends Reference
|
||||
# A class for project properties.
|
||||
|
@ -9,8 +10,11 @@ var tiles: Tiles
|
|||
var undos := 0 # The number of times we added undo properties
|
||||
var fill_color := Color(0)
|
||||
var has_changed := false setget _has_changed_changed
|
||||
var frames := [] setget _frames_changed # Array of Frames (that contain Cels)
|
||||
var layers := [] setget _layers_changed # Array of Layers
|
||||
# frames and layers Arrays should generally only be modified directly when
|
||||
# opening/creating a project. When modifiying the current project, use
|
||||
# the add/remove/move/swap_frames/layers methods
|
||||
var frames := [] # Array of Frames (that contain Cels)
|
||||
var layers := [] # Array of Layers
|
||||
var current_frame := 0 setget _frame_changed
|
||||
var current_layer := 0 setget _layer_changed
|
||||
var selected_cels := [[0, 0]] # Array of Arrays of 2 integers (frame & layer)
|
||||
|
@ -44,9 +48,6 @@ var file_format: int = Export.FileFormat.PNG
|
|||
var was_exported := false
|
||||
var export_overwrite := false
|
||||
|
||||
var frame_button_node = preload("res://src/UI/Timeline/FrameButton.tscn")
|
||||
var layer_button_node = preload("res://src/UI/Timeline/LayerButton.tscn")
|
||||
var cel_button_node = preload("res://src/UI/Timeline/CelButton.tscn")
|
||||
var animation_tag_node = preload("res://src/UI/Timeline/AnimationTagUI.tscn")
|
||||
|
||||
|
||||
|
@ -88,6 +89,8 @@ func remove() -> void:
|
|||
undo_redo.free()
|
||||
for guide in guides:
|
||||
guide.queue_free()
|
||||
# Prevents memory leak (due to the layers' project reference stopping ref counting from freeing)
|
||||
layers.clear()
|
||||
Global.projects.erase(self)
|
||||
|
||||
|
||||
|
@ -108,13 +111,11 @@ func new_empty_frame() -> Frame:
|
|||
var frame := Frame.new()
|
||||
var bottom_layer := true
|
||||
for l in layers: # Create as many cels as there are layers
|
||||
var image := Image.new()
|
||||
image.create(size.x, size.y, false, Image.FORMAT_RGBA8)
|
||||
if bottom_layer and fill_color.a > 0:
|
||||
image.fill(fill_color)
|
||||
frame.cels.append(Cel.new(image, 1))
|
||||
var cel: BaseCel = l.new_empty_cel()
|
||||
if cel is PixelCel and bottom_layer and fill_color.a > 0:
|
||||
cel.image.fill(fill_color)
|
||||
frame.cels.append(cel)
|
||||
bottom_layer = false
|
||||
|
||||
return frame
|
||||
|
||||
|
||||
|
@ -135,51 +136,7 @@ func _selection_offset_changed(value: Vector2) -> void:
|
|||
|
||||
|
||||
func change_project() -> void:
|
||||
# Remove old nodes
|
||||
for container in Global.layers_container.get_children():
|
||||
container.queue_free()
|
||||
|
||||
_remove_cel_buttons()
|
||||
|
||||
for frame_id in Global.frame_ids.get_children():
|
||||
Global.frame_ids.remove_child(frame_id)
|
||||
frame_id.queue_free()
|
||||
|
||||
# Create new ones
|
||||
for i in range(layers.size() - 1, -1, -1):
|
||||
# Create layer buttons
|
||||
var layer_container = layer_button_node.instance()
|
||||
layer_container.layer = i
|
||||
if layers[i].name == "":
|
||||
layers[i].name = tr("Layer") + " %s" % i
|
||||
|
||||
Global.layers_container.add_child(layer_container)
|
||||
layer_container.label.text = layers[i].name
|
||||
layer_container.line_edit.text = layers[i].name
|
||||
|
||||
var layer_cel_container := HBoxContainer.new()
|
||||
Global.frames_container.add_child(layer_cel_container)
|
||||
for j in range(frames.size()): # Create Cel buttons
|
||||
var cel_button = cel_button_node.instance()
|
||||
cel_button.frame = j
|
||||
cel_button.layer = i
|
||||
cel_button.get_child(0).texture = frames[j].cels[i].image_texture
|
||||
cel_button.pressed = j == current_frame and i == current_layer
|
||||
|
||||
layer_cel_container.add_child(cel_button)
|
||||
|
||||
for j in range(frames.size()): # Create frame buttons
|
||||
var button: Button = frame_button_node.instance()
|
||||
button.frame = j
|
||||
button.rect_min_size.x = Global.animation_timeline.cel_size
|
||||
button.text = str(j + 1)
|
||||
button.pressed = j == current_frame
|
||||
Global.frame_ids.add_child(button)
|
||||
|
||||
var layer_button = Global.layers_container.get_child(
|
||||
Global.layers_container.get_child_count() - 1 - current_layer
|
||||
)
|
||||
layer_button.pressed = true
|
||||
Global.animation_timeline.project_changed()
|
||||
|
||||
Global.current_frame_mark_label.text = "%s/%s" % [str(current_frame + 1), frames.size()]
|
||||
|
||||
|
@ -188,8 +145,7 @@ func change_project() -> void:
|
|||
Global.disable_button(
|
||||
Global.move_right_frame_button, frames.size() == 1 or current_frame == frames.size() - 1
|
||||
)
|
||||
_toggle_layer_buttons_layers()
|
||||
_toggle_layer_buttons_current_layer()
|
||||
toggle_layer_buttons()
|
||||
|
||||
self.animation_tags = animation_tags
|
||||
|
||||
|
@ -292,20 +248,8 @@ func change_project() -> void:
|
|||
func serialize() -> Dictionary:
|
||||
var layer_data := []
|
||||
for layer in layers:
|
||||
var linked_cels := []
|
||||
for cel in layer.linked_cels:
|
||||
linked_cels.append(frames.find(cel))
|
||||
|
||||
layer_data.append(
|
||||
{
|
||||
"name": layer.name,
|
||||
"visible": layer.visible,
|
||||
"locked": layer.locked,
|
||||
"new_cels_linked": layer.new_cels_linked,
|
||||
"linked_cels": linked_cels,
|
||||
"metadata": _serialize_metadata(layer)
|
||||
}
|
||||
)
|
||||
layer_data.append(layer.serialize())
|
||||
layer_data[-1]["metadata"] = _serialize_metadata(layer)
|
||||
|
||||
var tag_data := []
|
||||
for tag in animation_tags:
|
||||
|
@ -395,14 +339,19 @@ func deserialize(dict: Dictionary) -> void:
|
|||
tiles.y_basis.y = dict.tile_mode_y_basis_y
|
||||
if dict.has("save_path"):
|
||||
OpenSave.current_save_paths[Global.projects.find(self)] = dict.save_path
|
||||
if dict.has("frames"):
|
||||
if dict.has("frames") and dict.has("layers"):
|
||||
var frame_i := 0
|
||||
for frame in dict.frames:
|
||||
var cels := []
|
||||
var cel_i := 0
|
||||
for cel in frame.cels:
|
||||
var cel_class := Cel.new(Image.new(), cel.opacity)
|
||||
_deserialize_metadata(cel_class, cel)
|
||||
cels.append(cel_class)
|
||||
match int(dict.layers[cel_i].get("type", Global.LayerTypes.PIXEL)):
|
||||
Global.LayerTypes.PIXEL:
|
||||
cels.append(PixelCel.new(Image.new(), cel.opacity))
|
||||
Global.LayerTypes.GROUP:
|
||||
cels.append(GroupCel.new(cel.opacity))
|
||||
_deserialize_metadata(cels[cel_i], cel)
|
||||
cel_i += 1
|
||||
var duration := 1.0
|
||||
if frame.has("duration"):
|
||||
duration = frame.duration
|
||||
|
@ -414,25 +363,18 @@ func deserialize(dict: Dictionary) -> void:
|
|||
frames.append(frame_class)
|
||||
frame_i += 1
|
||||
|
||||
if dict.has("layers"):
|
||||
var layer_i := 0
|
||||
for saved_layer in dict.layers:
|
||||
var linked_cels := []
|
||||
for linked_cel_number in saved_layer.linked_cels:
|
||||
linked_cels.append(frames[linked_cel_number])
|
||||
var linked_cel: Cel = frames[linked_cel_number].cels[layer_i]
|
||||
linked_cel.image = linked_cels[0].cels[layer_i].image
|
||||
linked_cel.image_texture = linked_cels[0].cels[layer_i].image_texture
|
||||
var layer := Layer.new(
|
||||
saved_layer.name,
|
||||
saved_layer.visible,
|
||||
saved_layer.locked,
|
||||
saved_layer.new_cels_linked,
|
||||
linked_cels
|
||||
)
|
||||
_deserialize_metadata(layer, saved_layer)
|
||||
layers.append(layer)
|
||||
layer_i += 1
|
||||
for saved_layer in dict.layers:
|
||||
match int(saved_layer.get("type", Global.LayerTypes.PIXEL)):
|
||||
Global.LayerTypes.PIXEL:
|
||||
layers.append(PixelLayer.new(self))
|
||||
Global.LayerTypes.GROUP:
|
||||
layers.append(GroupLayer.new(self))
|
||||
# Parent references to other layers are created when deserializing
|
||||
# a layer, so loop again after creating them:
|
||||
for layer_i in dict.layers.size():
|
||||
layers[layer_i].index = layer_i
|
||||
layers[layer_i].deserialize(dict.layers[layer_i])
|
||||
_deserialize_metadata(layers[layer_i], dict.layers[layer_i])
|
||||
if dict.has("tags"):
|
||||
for tag in dict.tags:
|
||||
animation_tags.append(AnimationTag.new(tag.name, Color(tag.color), tag.from, tag.to))
|
||||
|
@ -502,84 +444,6 @@ func _size_changed(value: Vector2) -> void:
|
|||
size = value
|
||||
|
||||
|
||||
func _frames_changed(value: Array) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
frames = value
|
||||
selected_cels.clear()
|
||||
_remove_cel_buttons()
|
||||
|
||||
for frame_id in Global.frame_ids.get_children():
|
||||
Global.frame_ids.remove_child(frame_id)
|
||||
frame_id.queue_free()
|
||||
|
||||
for i in range(layers.size() - 1, -1, -1):
|
||||
var layer_cel_container := HBoxContainer.new()
|
||||
layer_cel_container.name = "FRAMESS " + str(i)
|
||||
Global.frames_container.add_child(layer_cel_container)
|
||||
for j in range(frames.size()):
|
||||
var cel_button = cel_button_node.instance()
|
||||
cel_button.frame = j
|
||||
cel_button.layer = i
|
||||
cel_button.get_child(0).texture = frames[j].cels[i].image_texture
|
||||
layer_cel_container.add_child(cel_button)
|
||||
|
||||
for j in range(frames.size()):
|
||||
var button: Button = frame_button_node.instance()
|
||||
button.frame = j
|
||||
button.rect_min_size.x = Global.animation_timeline.cel_size
|
||||
button.text = str(j + 1)
|
||||
Global.frame_ids.add_child(button)
|
||||
|
||||
_set_timeline_first_and_last_frames()
|
||||
|
||||
|
||||
func _layers_changed(value: Array) -> void:
|
||||
layers = value
|
||||
if Global.layers_changed_skip:
|
||||
Global.layers_changed_skip = false
|
||||
return
|
||||
|
||||
selected_cels.clear()
|
||||
|
||||
for container in Global.layers_container.get_children():
|
||||
container.queue_free()
|
||||
|
||||
_remove_cel_buttons()
|
||||
|
||||
for i in range(layers.size() - 1, -1, -1):
|
||||
var layer_button: LayerButton = layer_button_node.instance()
|
||||
layer_button.layer = i
|
||||
if layers[i].name == "":
|
||||
layers[i].name = tr("Layer") + " %s" % i
|
||||
|
||||
Global.layers_container.add_child(layer_button)
|
||||
layer_button.label.text = layers[i].name
|
||||
layer_button.line_edit.text = layers[i].name
|
||||
|
||||
var layer_cel_container := HBoxContainer.new()
|
||||
layer_cel_container.name = "LAYERSSS " + str(i)
|
||||
Global.frames_container.add_child(layer_cel_container)
|
||||
for j in range(frames.size()):
|
||||
var cel_button = cel_button_node.instance()
|
||||
cel_button.frame = j
|
||||
cel_button.layer = i
|
||||
cel_button.get_child(0).texture = frames[j].cels[i].image_texture
|
||||
layer_cel_container.add_child(cel_button)
|
||||
|
||||
var layer_button = Global.layers_container.get_child(
|
||||
Global.layers_container.get_child_count() - 1 - current_layer
|
||||
)
|
||||
layer_button.pressed = true
|
||||
self.current_frame = current_frame # Call frame_changed to update UI
|
||||
_toggle_layer_buttons_layers()
|
||||
|
||||
|
||||
func _remove_cel_buttons() -> void:
|
||||
for container in Global.frames_container.get_children():
|
||||
Global.frames_container.remove_child(container)
|
||||
container.queue_free()
|
||||
|
||||
|
||||
func _frame_changed(value: int) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
current_frame = value
|
||||
|
@ -596,32 +460,25 @@ func _frame_changed(value: int) -> void:
|
|||
selected_cels.append([current_frame, current_layer])
|
||||
# Select the new frame
|
||||
for cel in selected_cels:
|
||||
var current_frame_tmp: int = cel[0]
|
||||
var current_layer_tmp: int = cel[1]
|
||||
if current_frame_tmp < Global.frame_ids.get_child_count():
|
||||
var frame_button: BaseButton = Global.frame_ids.get_child(current_frame_tmp)
|
||||
var frame: int = cel[0]
|
||||
var layer: int = cel[1]
|
||||
if frame < Global.frame_ids.get_child_count():
|
||||
var frame_button: BaseButton = Global.frame_ids.get_child(frame)
|
||||
frame_button.pressed = true
|
||||
|
||||
var container_child_count: int = Global.frames_container.get_child_count()
|
||||
if current_layer_tmp < container_child_count:
|
||||
var container = Global.frames_container.get_child(
|
||||
container_child_count - 1 - current_layer_tmp
|
||||
)
|
||||
if current_frame_tmp < container.get_child_count():
|
||||
var fbutton = container.get_child(current_frame_tmp)
|
||||
fbutton.pressed = true
|
||||
|
||||
Global.disable_button(Global.remove_frame_button, frames.size() == 1)
|
||||
Global.disable_button(Global.move_left_frame_button, frames.size() == 1 or current_frame == 0)
|
||||
Global.disable_button(
|
||||
Global.move_right_frame_button, frames.size() == 1 or current_frame == frames.size() - 1
|
||||
)
|
||||
if layer < container_child_count:
|
||||
var container = Global.frames_container.get_child(container_child_count - 1 - layer)
|
||||
if frame < container.get_child_count():
|
||||
var cel_button = container.get_child(frame)
|
||||
cel_button.pressed = true
|
||||
|
||||
if current_frame < frames.size():
|
||||
var cel_opacity: float = frames[current_frame].cels[current_layer].opacity
|
||||
Global.layer_opacity_slider.value = cel_opacity * 100
|
||||
Global.layer_opacity_spinbox.value = cel_opacity * 100
|
||||
|
||||
toggle_frame_buttons()
|
||||
Global.canvas.update()
|
||||
Global.transparent_checker.update_rect()
|
||||
|
||||
|
@ -630,7 +487,7 @@ func _layer_changed(value: int) -> void:
|
|||
Global.canvas.selection.transform_content_confirm()
|
||||
current_layer = value
|
||||
|
||||
_toggle_layer_buttons_current_layer()
|
||||
toggle_layer_buttons()
|
||||
|
||||
yield(Global.get_tree().create_timer(0.01), "timeout")
|
||||
self.current_frame = current_frame # Call frame_changed to update UI
|
||||
|
@ -638,48 +495,44 @@ func _layer_changed(value: int) -> void:
|
|||
layer_button.pressed = false
|
||||
|
||||
for cel in selected_cels:
|
||||
var current_layer_tmp: int = cel[1]
|
||||
if current_layer_tmp < Global.layers_container.get_child_count():
|
||||
var layer: int = cel[1]
|
||||
if layer < Global.layers_container.get_child_count():
|
||||
var layer_button = Global.layers_container.get_child(
|
||||
Global.layers_container.get_child_count() - 1 - current_layer_tmp
|
||||
Global.layers_container.get_child_count() - 1 - layer
|
||||
)
|
||||
layer_button.pressed = true
|
||||
|
||||
|
||||
func _toggle_layer_buttons_layers() -> void:
|
||||
if !layers:
|
||||
func toggle_frame_buttons() -> void:
|
||||
Global.disable_button(Global.remove_frame_button, frames.size() == 1)
|
||||
Global.disable_button(Global.move_left_frame_button, frames.size() == 1 or current_frame == 0)
|
||||
Global.disable_button(
|
||||
Global.move_right_frame_button, frames.size() == 1 or current_frame == frames.size() - 1
|
||||
)
|
||||
|
||||
|
||||
func toggle_layer_buttons() -> void:
|
||||
if layers.empty() or current_layer >= layers.size():
|
||||
return
|
||||
if layers[current_layer].locked:
|
||||
Global.disable_button(Global.remove_layer_button, true)
|
||||
var child_count: int = layers[current_layer].get_child_count(true)
|
||||
|
||||
if layers.size() == 1:
|
||||
Global.disable_button(Global.remove_layer_button, true)
|
||||
Global.disable_button(Global.move_up_layer_button, true)
|
||||
Global.disable_button(Global.move_down_layer_button, true)
|
||||
Global.disable_button(Global.merge_down_layer_button, true)
|
||||
elif !layers[current_layer].locked:
|
||||
Global.disable_button(Global.remove_layer_button, false)
|
||||
|
||||
|
||||
func _toggle_layer_buttons_current_layer() -> void:
|
||||
if current_layer < layers.size() - 1:
|
||||
Global.disable_button(Global.move_up_layer_button, false)
|
||||
else:
|
||||
Global.disable_button(Global.move_up_layer_button, true)
|
||||
|
||||
if current_layer > 0:
|
||||
Global.disable_button(Global.move_down_layer_button, false)
|
||||
Global.disable_button(Global.merge_down_layer_button, false)
|
||||
else:
|
||||
Global.disable_button(Global.move_down_layer_button, true)
|
||||
Global.disable_button(Global.merge_down_layer_button, true)
|
||||
|
||||
if current_layer < layers.size():
|
||||
if layers[current_layer].locked:
|
||||
Global.disable_button(Global.remove_layer_button, true)
|
||||
else:
|
||||
if layers.size() > 1:
|
||||
Global.disable_button(Global.remove_layer_button, false)
|
||||
Global.disable_button(
|
||||
Global.remove_layer_button,
|
||||
layers[current_layer].is_locked_in_hierarchy() or layers.size() == child_count + 1
|
||||
)
|
||||
Global.disable_button(Global.move_up_layer_button, current_layer == layers.size() - 1)
|
||||
Global.disable_button(
|
||||
Global.move_down_layer_button,
|
||||
current_layer == child_count and not is_instance_valid(layers[current_layer].parent)
|
||||
)
|
||||
Global.disable_button(
|
||||
Global.merge_down_layer_button,
|
||||
(
|
||||
current_layer == child_count
|
||||
or layers[current_layer] is GroupLayer
|
||||
or layers[current_layer - 1] is GroupLayer
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
func _animation_tags_changed(value: Array) -> void:
|
||||
|
@ -735,6 +588,7 @@ func is_empty() -> bool:
|
|||
return (
|
||||
frames.size() == 1
|
||||
and layers.size() == 1
|
||||
and layers[0] is PixelLayer
|
||||
and frames[0].cels[0].image.is_invisible()
|
||||
and animation_tags.size() == 0
|
||||
)
|
||||
|
@ -745,15 +599,10 @@ func duplicate_layers() -> Array:
|
|||
# Loop through the array to create new classes for each element, so that they
|
||||
# won't be the same as the original array's classes. Needed for undo/redo to work properly.
|
||||
for i in new_layers.size():
|
||||
var new_linked_cels = new_layers[i].linked_cels.duplicate()
|
||||
new_layers[i] = Layer.new(
|
||||
new_layers[i].name,
|
||||
new_layers[i].visible,
|
||||
new_layers[i].locked,
|
||||
new_layers[i].new_cels_linked,
|
||||
new_linked_cels
|
||||
)
|
||||
|
||||
new_layers[i] = new_layers[i].copy()
|
||||
for l in new_layers:
|
||||
if is_instance_valid(l.parent):
|
||||
l.parent = new_layers[l.parent.index] # Update the parent to the new copy of the parent
|
||||
return new_layers
|
||||
|
||||
|
||||
|
@ -776,3 +625,236 @@ func can_pixel_get_drawn(
|
|||
return image.is_pixel_selected(pixel)
|
||||
else:
|
||||
return true
|
||||
|
||||
|
||||
# Timeline modifications
|
||||
# Modifying layers or frames Arrays on the current project should generally only be done
|
||||
# through these methods.
|
||||
# These allow you to add/remove/move/swap frames/layers/cels. It updates the Animation Timeline
|
||||
# UI, and updates indices. These are designed to be reversible, meaning that to undo an add, you
|
||||
# use remove, and vise versa. To undo a move or swap, use move or swap with the paramaters swapped.
|
||||
|
||||
|
||||
func add_frames(new_frames: Array, indices: Array) -> void: # indices should be in ascending order
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
for i in new_frames.size():
|
||||
frames.insert(indices[i], new_frames[i])
|
||||
Global.animation_timeline.project_frame_added(indices[i])
|
||||
# Update the frames and frame buttons:
|
||||
for f in frames.size():
|
||||
Global.frame_ids.get_child(f).frame = f
|
||||
Global.frame_ids.get_child(f).text = str(f + 1)
|
||||
# Update the cel buttons:
|
||||
for l in layers.size():
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).frame = f
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
_set_timeline_first_and_last_frames()
|
||||
|
||||
|
||||
func remove_frames(indices: Array) -> void: # indices should be in ascending order
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
for i in indices.size():
|
||||
# With each removed index, future indices need to be lowered, so subtract by i
|
||||
frames.remove(indices[i] - i)
|
||||
Global.animation_timeline.project_frame_removed(indices[i] - i)
|
||||
# Update the frames and frame buttons:
|
||||
for f in frames.size():
|
||||
Global.frame_ids.get_child(f).frame = f
|
||||
Global.frame_ids.get_child(f).text = str(f + 1)
|
||||
# Update the cel buttons:
|
||||
for l in layers.size():
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).frame = f
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
_set_timeline_first_and_last_frames()
|
||||
|
||||
|
||||
func move_frame(from_index: int, to_index: int) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
var frame = frames[from_index]
|
||||
frames.remove(from_index)
|
||||
Global.animation_timeline.project_frame_removed(from_index)
|
||||
frames.insert(to_index, frame)
|
||||
Global.animation_timeline.project_frame_added(to_index)
|
||||
# Update the frames and frame buttons:
|
||||
for f in frames.size():
|
||||
Global.frame_ids.get_child(f).frame = f
|
||||
Global.frame_ids.get_child(f).text = str(f + 1)
|
||||
# Update the cel buttons:
|
||||
for l in layers.size():
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).frame = f
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
_set_timeline_first_and_last_frames()
|
||||
|
||||
|
||||
func swap_frame(a_index: int, b_index: int) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
var temp: Frame = frames[a_index]
|
||||
frames[a_index] = frames[b_index]
|
||||
frames[b_index] = temp
|
||||
Global.animation_timeline.project_frame_removed(a_index)
|
||||
Global.animation_timeline.project_frame_added(a_index)
|
||||
Global.animation_timeline.project_frame_removed(b_index)
|
||||
Global.animation_timeline.project_frame_added(b_index)
|
||||
_set_timeline_first_and_last_frames()
|
||||
|
||||
|
||||
func add_layers(new_layers: Array, indices: Array, cels: Array) -> void: # cels is 2d Array of cels
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
for i in indices.size():
|
||||
layers.insert(indices[i], new_layers[i])
|
||||
for f in frames.size():
|
||||
frames[f].cels.insert(indices[i], cels[i][f])
|
||||
new_layers[i].project = self
|
||||
Global.animation_timeline.project_layer_added(indices[i])
|
||||
# Update the layer indices and layer/cel buttons:
|
||||
for l in layers.size():
|
||||
layers[l].index = l
|
||||
Global.layers_container.get_child(layers.size() - 1 - l).layer = l
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).layer = l
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
toggle_layer_buttons()
|
||||
|
||||
|
||||
func remove_layers(indices: Array) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
for i in indices.size():
|
||||
# With each removed index, future indices need to be lowered, so subtract by i
|
||||
layers.remove(indices[i] - i)
|
||||
for frame in frames:
|
||||
frame.cels.remove(indices[i] - i)
|
||||
Global.animation_timeline.project_layer_removed(indices[i] - i)
|
||||
# Update the layer indices and layer/cel buttons:
|
||||
for l in layers.size():
|
||||
layers[l].index = l
|
||||
Global.layers_container.get_child(layers.size() - 1 - l).layer = l
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).layer = l
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
toggle_layer_buttons()
|
||||
|
||||
|
||||
# from_indices and to_indicies should be in ascending order
|
||||
func move_layers(from_indices: Array, to_indices: Array, to_parents: Array) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
var removed_layers := []
|
||||
var removed_cels := [] # 2D array of cels (an array for each layer removed)
|
||||
|
||||
for i in from_indices.size():
|
||||
# With each removed index, future indices need to be lowered, so subtract by i
|
||||
removed_layers.append(layers.pop_at(from_indices[i] - i))
|
||||
removed_layers[i].parent = to_parents[i] # parents must be set before UI created in next loop
|
||||
removed_cels.append([])
|
||||
for frame in frames:
|
||||
removed_cels[i].append(frame.cels.pop_at(from_indices[i] - i))
|
||||
Global.animation_timeline.project_layer_removed(from_indices[i] - i)
|
||||
for i in to_indices.size():
|
||||
layers.insert(to_indices[i], removed_layers[i])
|
||||
for f in frames.size():
|
||||
frames[f].cels.insert(to_indices[i], removed_cels[i][f])
|
||||
Global.animation_timeline.project_layer_added(to_indices[i])
|
||||
# Update the layer indices and layer/cel buttons:
|
||||
for l in layers.size():
|
||||
layers[l].index = l
|
||||
Global.layers_container.get_child(layers.size() - 1 - l).layer = l
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).layer = l
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
toggle_layer_buttons()
|
||||
|
||||
|
||||
# "a" and "b" should both contain "from", "to", and "to_parents" arrays.
|
||||
# (Using dictionaries because there seems to be a limit of 5 arguments for do/undo method calls)
|
||||
func swap_layers(a: Dictionary, b: Dictionary) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
var a_layers := []
|
||||
var b_layers := []
|
||||
var a_cels := [] # 2D array of cels (an array for each layer removed)
|
||||
var b_cels := [] # 2D array of cels (an array for each layer removed)
|
||||
for i in a.from.size():
|
||||
a_layers.append(layers.pop_at(a.from[i] - i))
|
||||
Global.animation_timeline.project_layer_removed(a.from[i] - i)
|
||||
a_layers[i].parent = a.to_parents[i] # All parents must be set early, before creating buttons
|
||||
a_cels.append([])
|
||||
for frame in frames:
|
||||
a_cels[i].append(frame.cels.pop_at(a.from[i] - i))
|
||||
for i in b.from.size():
|
||||
var index = (b.from[i] - i) if a.from[0] > b.from[0] else (b.from[i] - i - a.from.size())
|
||||
b_layers.append(layers.pop_at(index))
|
||||
Global.animation_timeline.project_layer_removed(index)
|
||||
b_layers[i].parent = b.to_parents[i] # All parents must be set early, before creating buttons
|
||||
b_cels.append([])
|
||||
for frame in frames:
|
||||
b_cels[i].append(frame.cels.pop_at(index))
|
||||
|
||||
for i in a_layers.size():
|
||||
var index = a.to[i] if a.to[0] < b.to[0] else (a.to[i] - b.to.size())
|
||||
layers.insert(index, a_layers[i])
|
||||
for f in frames.size():
|
||||
frames[f].cels.insert(index, a_cels[i][f])
|
||||
Global.animation_timeline.project_layer_added(index)
|
||||
for i in b_layers.size():
|
||||
layers.insert(b.to[i], b_layers[i])
|
||||
for f in frames.size():
|
||||
frames[f].cels.insert(b.to[i], b_cels[i][f])
|
||||
Global.animation_timeline.project_layer_added(b.to[i])
|
||||
|
||||
# Update the layer indices and layer/cel buttons:
|
||||
for l in layers.size():
|
||||
layers[l].index = l
|
||||
Global.layers_container.get_child(layers.size() - 1 - l).layer = l
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - l)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).layer = l
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
toggle_layer_buttons()
|
||||
|
||||
|
||||
func move_cel(from_frame: int, to_frame: int, layer: int) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
var cel: BaseCel = frames[from_frame].cels[layer]
|
||||
if from_frame < to_frame:
|
||||
for f in range(from_frame, to_frame): # Forward range
|
||||
frames[f].cels[layer] = frames[f + 1].cels[layer] # Move left
|
||||
else:
|
||||
for f in range(from_frame, to_frame, -1): # Backward range
|
||||
frames[f].cels[layer] = frames[f - 1].cels[layer] # Move right
|
||||
frames[to_frame].cels[layer] = cel
|
||||
Global.animation_timeline.project_cel_removed(from_frame, layer)
|
||||
Global.animation_timeline.project_cel_added(to_frame, layer)
|
||||
|
||||
# Update the cel buttons for this layer:
|
||||
var layer_cel_container = Global.frames_container.get_child(layers.size() - 1 - layer)
|
||||
for f in frames.size():
|
||||
layer_cel_container.get_child(f).frame = f
|
||||
layer_cel_container.get_child(f).button_setup()
|
||||
|
||||
|
||||
func swap_cel(a_frame: int, a_layer: int, b_frame: int, b_layer: int) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
selected_cels.clear()
|
||||
var temp: BaseCel = frames[a_frame].cels[a_layer]
|
||||
frames[a_frame].cels[a_layer] = frames[b_frame].cels[b_layer]
|
||||
frames[b_frame].cels[b_layer] = temp
|
||||
Global.animation_timeline.project_cel_removed(a_frame, a_layer)
|
||||
Global.animation_timeline.project_cel_added(a_frame, a_layer)
|
||||
Global.animation_timeline.project_cel_removed(b_frame, b_layer)
|
||||
Global.animation_timeline.project_cel_added(b_frame, b_layer)
|
||||
|
|
|
@ -26,10 +26,10 @@ func _ready() -> void:
|
|||
|
||||
Global.window_title = tr("untitled") + " - Pixelorama " + Global.current_version
|
||||
|
||||
Global.current_project.layers.append(Layer.new())
|
||||
var frame: Frame = Global.current_project.new_empty_frame()
|
||||
Global.current_project.frames.append(frame)
|
||||
Global.current_project.layers = Global.current_project.layers
|
||||
Global.current_project.layers.append(PixelLayer.new(Global.current_project))
|
||||
Global.current_project.frames.append(Global.current_project.new_empty_frame())
|
||||
Global.animation_timeline.project_changed()
|
||||
Global.current_project.toggle_frame_buttons()
|
||||
|
||||
Import.import_brushes(Global.directory_module.get_brushes_search_path_in_order())
|
||||
Import.import_patterns(Global.directory_module.get_patterns_search_path_in_order())
|
||||
|
|
|
@ -87,14 +87,14 @@ func _get_draw_rect() -> Rect2:
|
|||
|
||||
func _get_draw_image() -> Image:
|
||||
var project: Project = Global.current_project
|
||||
return project.frames[project.current_frame].cels[project.current_layer].image
|
||||
return project.frames[project.current_frame].cels[project.current_layer].get_image()
|
||||
|
||||
|
||||
func _get_selected_draw_images() -> Array: # Array of Images
|
||||
var images := []
|
||||
var project: Project = Global.current_project
|
||||
for cel_index in project.selected_cels:
|
||||
var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
if project.layers[cel_index[1]].can_layer_get_drawn():
|
||||
images.append(cel.image)
|
||||
return images
|
||||
|
|
|
@ -577,9 +577,11 @@ func _get_undo_data() -> Dictionary:
|
|||
cels.append(project.frames[cel_index[0]].cels[cel_index[1]])
|
||||
else:
|
||||
for frame in project.frames:
|
||||
var cel: Cel = frame.cels[project.current_layer]
|
||||
var cel: PixelCel = frame.cels[project.current_layer]
|
||||
cels.append(cel)
|
||||
for cel in cels:
|
||||
if cel is GroupCel:
|
||||
continue
|
||||
var image: Image = cel.image
|
||||
image.unlock()
|
||||
data[image] = image.data
|
||||
|
|
|
@ -153,7 +153,7 @@ func _get_undo_data() -> Dictionary:
|
|||
cels.append(project.frames[cel_index[0]].cels[cel_index[1]])
|
||||
else:
|
||||
for frame in project.frames:
|
||||
var cel: Cel = frame.cels[project.current_layer]
|
||||
var cel: PixelCel = frame.cels[project.current_layer]
|
||||
cels.append(cel)
|
||||
for cel in cels:
|
||||
var image: Image = cel.image
|
||||
|
|
|
@ -41,8 +41,10 @@ func _draw() -> void:
|
|||
draw_set_transform(position_tmp, rotation, scale_tmp)
|
||||
# Draw current frame layers
|
||||
for i in range(Global.current_project.layers.size()):
|
||||
if current_cels[i] is GroupCel:
|
||||
continue
|
||||
var modulate_color := Color(1, 1, 1, current_cels[i].opacity)
|
||||
if Global.current_project.layers[i].visible: # if it's visible
|
||||
if Global.current_project.layers[i].is_visible_in_hierarchy():
|
||||
if i == current_layer:
|
||||
draw_texture(current_cels[i].image_texture, move_preview_location, modulate_color)
|
||||
else:
|
||||
|
@ -121,16 +123,8 @@ func update_texture(layer_i: int, frame_i := -1, project: Project = Global.curre
|
|||
frame_i = project.current_frame
|
||||
|
||||
if frame_i < project.frames.size() and layer_i < project.layers.size():
|
||||
var current_cel: Cel = project.frames[frame_i].cels[layer_i]
|
||||
current_cel.image_texture.set_data(current_cel.image)
|
||||
|
||||
if project == Global.current_project:
|
||||
var container_index = Global.frames_container.get_child_count() - 1 - layer_i
|
||||
var layer_cel_container = Global.frames_container.get_child(container_index)
|
||||
var cel_button = layer_cel_container.get_child(frame_i)
|
||||
var cel_texture_rect: TextureRect
|
||||
cel_texture_rect = cel_button.find_node("CelTexture")
|
||||
cel_texture_rect.texture = current_cel.image_texture
|
||||
var current_cel: BaseCel = project.frames[frame_i].cels[layer_i]
|
||||
current_cel.update_texture()
|
||||
|
||||
|
||||
func update_selected_cels_textures(project: Project = Global.current_project) -> void:
|
||||
|
@ -138,15 +132,8 @@ func update_selected_cels_textures(project: Project = Global.current_project) ->
|
|||
var frame_index: int = cel_index[0]
|
||||
var layer_index: int = cel_index[1]
|
||||
if frame_index < project.frames.size() and layer_index < project.layers.size():
|
||||
var current_cel: Cel = project.frames[frame_index].cels[layer_index]
|
||||
current_cel.image_texture.set_data(current_cel.image)
|
||||
|
||||
if project == Global.current_project:
|
||||
var container_index = Global.frames_container.get_child_count() - 1 - layer_index
|
||||
var layer_cel_container = Global.frames_container.get_child(container_index)
|
||||
var cel_button = layer_cel_container.get_child(frame_index)
|
||||
var cel_texture_rect: TextureRect = cel_button.find_node("CelTexture")
|
||||
cel_texture_rect.texture = current_cel.image_texture
|
||||
var current_cel: BaseCel = project.frames[frame_index].cels[layer_index]
|
||||
current_cel.update_texture()
|
||||
|
||||
|
||||
func refresh_onion() -> void:
|
||||
|
|
|
@ -20,8 +20,13 @@ func _draw() -> void:
|
|||
|
||||
# Draw current frame layers
|
||||
for i in range(current_cels.size()):
|
||||
if current_cels[i] is GroupCel:
|
||||
continue
|
||||
var modulate_color := Color(1, 1, 1, current_cels[i].opacity)
|
||||
if i < current_project.layers.size() and current_project.layers[i].visible:
|
||||
if (
|
||||
i < current_project.layers.size()
|
||||
and current_project.layers[i].is_visible_in_hierarchy()
|
||||
):
|
||||
draw_texture(current_cels[i].image_texture, Vector2.ZERO, modulate_color)
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,11 @@ extends Node2D
|
|||
func _draw() -> void:
|
||||
var current_cels: Array = Global.current_project.frames[Global.current_project.current_frame].cels
|
||||
for i in range(Global.current_project.layers.size()):
|
||||
if Global.current_project.layers[i].visible and current_cels[i].opacity > 0:
|
||||
if current_cels[i] is GroupCel:
|
||||
continue
|
||||
if (
|
||||
Global.current_project.layers[i].is_visible_in_hierarchy()
|
||||
and current_cels[i].opacity > 0
|
||||
):
|
||||
var modulate_color := Color(1, 1, 1, current_cels[i].opacity)
|
||||
draw_texture(current_cels[i].image_texture, Vector2.ZERO, modulate_color)
|
||||
|
|
|
@ -28,8 +28,8 @@ func _draw() -> void:
|
|||
if change == clamp(change, 0, Global.current_project.frames.size() - 1):
|
||||
var layer_i := 0
|
||||
for cel in Global.current_project.frames[change].cels:
|
||||
var layer: Layer = Global.current_project.layers[layer_i]
|
||||
if layer.visible:
|
||||
var layer: BaseLayer = Global.current_project.layers[layer_i]
|
||||
if layer.is_visible_in_hierarchy():
|
||||
# Ignore layer if it has the "_io" suffix in its name (case in-sensitive)
|
||||
if not (layer.name.to_lower().ends_with("_io")):
|
||||
color.a = 0.6 / i
|
||||
|
|
|
@ -98,7 +98,7 @@ func _input(event: InputEvent) -> void:
|
|||
if Global.cross_cursor:
|
||||
cursor = Control.CURSOR_CROSS
|
||||
var project: Project = Global.current_project
|
||||
var layer: Layer = project.layers[project.current_layer]
|
||||
var layer: BaseLayer = project.layers[project.current_layer]
|
||||
if not layer.can_layer_get_drawn():
|
||||
cursor = Control.CURSOR_FORBIDDEN
|
||||
|
||||
|
@ -644,7 +644,9 @@ func _get_selected_draw_images() -> Array: # Array of Images
|
|||
var images := []
|
||||
var project: Project = Global.current_project
|
||||
for cel_index in project.selected_cels:
|
||||
var cel: Cel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
var cel: BaseCel = project.frames[cel_index[0]].cels[cel_index[1]]
|
||||
if not cel is PixelCel:
|
||||
continue
|
||||
if project.layers[cel_index[1]].can_layer_get_drawn():
|
||||
images.append(cel.image)
|
||||
return images
|
||||
|
@ -665,7 +667,7 @@ func copy() -> void:
|
|||
var cl_big_bounding_rectangle := Rect2()
|
||||
var cl_selection_offset := Vector2.ZERO
|
||||
|
||||
var image: Image = project.frames[project.current_frame].cels[project.current_layer].image
|
||||
var image: Image = project.frames[project.current_frame].cels[project.current_layer].get_image()
|
||||
var to_copy := Image.new()
|
||||
if !project.has_selection:
|
||||
to_copy.copy_from(image)
|
||||
|
|
|
@ -108,10 +108,9 @@ func _on_CreateNewImage_confirmed() -> void:
|
|||
proj_name = tr("untitled")
|
||||
|
||||
var new_project := Project.new([], proj_name, Vector2(width, height).floor())
|
||||
new_project.layers.append(Layer.new())
|
||||
new_project.layers.append(PixelLayer.new(new_project))
|
||||
new_project.fill_color = fill_color
|
||||
var frame: Frame = new_project.new_empty_frame()
|
||||
new_project.frames.append(frame)
|
||||
new_project.frames.append(new_project.new_empty_frame())
|
||||
Global.projects.append(new_project)
|
||||
Global.tabs.current_tab = Global.tabs.get_tab_count() - 1
|
||||
Global.canvas.camera_zoom()
|
||||
|
|
|
@ -22,7 +22,7 @@ func _on_ResizeCanvas_about_to_show() -> void:
|
|||
|
||||
var layer_i := 0
|
||||
for cel in Global.current_project.frames[Global.current_project.current_frame].cels:
|
||||
if Global.current_project.layers[layer_i].visible:
|
||||
if cel is PixelCel and Global.current_project.layers[layer_i].is_visible_in_hierarchy():
|
||||
var cel_image := Image.new()
|
||||
cel_image.copy_from(cel.image)
|
||||
cel_image.lock()
|
||||
|
|
|
@ -5,7 +5,7 @@ enum ImageImportOptions {
|
|||
SPRITESHEET_TAB,
|
||||
SPRITESHEET_LAYER,
|
||||
NEW_FRAME,
|
||||
REPLACE_FRAME,
|
||||
REPLACE_CEL,
|
||||
NEW_LAYER,
|
||||
PALETTE,
|
||||
BRUSH,
|
||||
|
@ -29,7 +29,7 @@ onready var frame_size_label: Label = $VBoxContainer/SizeContainer/FrameSizeLabe
|
|||
onready var spritesheet_tab_options = $VBoxContainer/HBoxContainer/SpritesheetTabOptions
|
||||
onready var spritesheet_lay_opt = $VBoxContainer/HBoxContainer/SpritesheetLayerOptions
|
||||
onready var new_frame_options = $VBoxContainer/HBoxContainer/NewFrameOptions
|
||||
onready var replace_frame_options = $VBoxContainer/HBoxContainer/ReplaceFrameOptions
|
||||
onready var replace_cel_options = $VBoxContainer/HBoxContainer/ReplaceCelOptions
|
||||
onready var new_layer_options = $VBoxContainer/HBoxContainer/NewLayerOptions
|
||||
onready var new_brush_options = $VBoxContainer/HBoxContainer/NewBrushOptions
|
||||
onready var new_brush_name = $VBoxContainer/HBoxContainer/NewBrushOptions/BrushName
|
||||
|
@ -47,7 +47,7 @@ func _on_PreviewDialog_about_to_show() -> void:
|
|||
import_options.add_item("Spritesheet (new project)")
|
||||
import_options.add_item("Spritesheet (new layer)")
|
||||
import_options.add_item("New frame")
|
||||
import_options.add_item("Replace frame")
|
||||
import_options.add_item("Replace cel")
|
||||
import_options.add_item("New layer")
|
||||
import_options.add_item("New palette")
|
||||
import_options.add_item("New brush")
|
||||
|
@ -129,13 +129,13 @@ func _on_PreviewDialog_confirmed() -> void:
|
|||
)
|
||||
|
||||
elif current_import_option == ImageImportOptions.NEW_FRAME:
|
||||
var layer_index: int = new_frame_options.get_node("AtLayerSpinbox").value
|
||||
var layer_index: int = new_frame_options.get_node("AtLayerOption").get_selected_id()
|
||||
OpenSave.open_image_as_new_frame(image, layer_index)
|
||||
|
||||
elif current_import_option == ImageImportOptions.REPLACE_FRAME:
|
||||
var layer_index: int = replace_frame_options.get_node("AtLayerSpinbox").value
|
||||
var frame_index: int = replace_frame_options.get_node("AtFrameSpinbox").value - 1
|
||||
OpenSave.open_image_at_frame(image, layer_index, frame_index)
|
||||
elif current_import_option == ImageImportOptions.REPLACE_CEL:
|
||||
var layer_index: int = replace_cel_options.get_node("AtLayerOption").get_selected_id()
|
||||
var frame_index: int = replace_cel_options.get_node("AtFrameSpinbox").value - 1
|
||||
OpenSave.open_image_at_cel(image, layer_index, frame_index)
|
||||
|
||||
elif current_import_option == ImageImportOptions.NEW_LAYER:
|
||||
var frame_index: int = new_layer_options.get_node("AtFrameSpinbox").value - 1
|
||||
|
@ -204,15 +204,15 @@ func synchronize() -> void:
|
|||
).value)
|
||||
|
||||
elif id == ImageImportOptions.NEW_FRAME:
|
||||
dialog.new_frame_options.get_node("AtLayerSpinbox").value = (new_frame_options.get_node(
|
||||
"AtLayerSpinbox"
|
||||
).value)
|
||||
dialog.new_frame_options.get_node("AtLayerOption").selected = (new_frame_options.get_node(
|
||||
"AtLayerOption"
|
||||
).selected)
|
||||
|
||||
elif id == ImageImportOptions.REPLACE_FRAME:
|
||||
dialog.replace_frame_options.get_node("AtLayerSpinbox").value = (replace_frame_options.get_node(
|
||||
"AtLayerSpinbox"
|
||||
).value)
|
||||
dialog.replace_frame_options.get_node("AtFrameSpinbox").value = (replace_frame_options.get_node(
|
||||
elif id == ImageImportOptions.REPLACE_CEL:
|
||||
dialog.replace_cel_options.get_node("AtLayerOption").selected = (replace_cel_options.get_node(
|
||||
"AtLayerOption"
|
||||
).selected)
|
||||
dialog.replace_cel_options.get_node("AtFrameSpinbox").value = (replace_cel_options.get_node(
|
||||
"AtFrameSpinbox"
|
||||
).value)
|
||||
|
||||
|
@ -236,7 +236,7 @@ func _on_ImportOption_item_selected(id: int) -> void:
|
|||
spritesheet_tab_options.visible = false
|
||||
spritesheet_lay_opt.visible = false
|
||||
new_frame_options.visible = false
|
||||
replace_frame_options.visible = false
|
||||
replace_cel_options.visible = false
|
||||
new_layer_options.visible = false
|
||||
new_brush_options.visible = false
|
||||
texture_rect.get_child(0).visible = false
|
||||
|
@ -260,18 +260,33 @@ func _on_ImportOption_item_selected(id: int) -> void:
|
|||
|
||||
elif id == ImageImportOptions.NEW_FRAME:
|
||||
new_frame_options.visible = true
|
||||
new_frame_options.get_node("AtLayerSpinbox").max_value = (
|
||||
Global.current_project.layers.size()
|
||||
- 1
|
||||
)
|
||||
|
||||
elif id == ImageImportOptions.REPLACE_FRAME:
|
||||
replace_frame_options.visible = true
|
||||
replace_frame_options.get_node("AtLayerSpinbox").max_value = (
|
||||
Global.current_project.layers.size()
|
||||
- 1
|
||||
)
|
||||
var at_frame_spinbox: SpinBox = replace_frame_options.get_node("AtFrameSpinbox")
|
||||
# Fill the at layer option button:
|
||||
var at_layer_option: OptionButton = new_frame_options.get_node("AtLayerOption")
|
||||
var layers := Global.current_project.layers.duplicate()
|
||||
layers.invert()
|
||||
var i := 0
|
||||
for l in layers:
|
||||
if not l is PixelLayer:
|
||||
continue
|
||||
at_layer_option.add_item(l.name, l.index)
|
||||
at_layer_option.set_item_tooltip(i, l.get_layer_path())
|
||||
i += 1
|
||||
at_layer_option.selected = at_layer_option.get_item_count() - 1
|
||||
elif id == ImageImportOptions.REPLACE_CEL:
|
||||
replace_cel_options.visible = true
|
||||
# Fill the at layer option button:
|
||||
var at_layer_option: OptionButton = replace_cel_options.get_node("AtLayerOption")
|
||||
var layers := Global.current_project.layers.duplicate()
|
||||
layers.invert()
|
||||
var i := 0
|
||||
for l in layers:
|
||||
if not l is PixelLayer:
|
||||
continue
|
||||
at_layer_option.add_item(l.name, l.index)
|
||||
at_layer_option.set_item_tooltip(i, l.get_layer_path())
|
||||
i += 1
|
||||
at_layer_option.selected = at_layer_option.get_item_count() - 1
|
||||
var at_frame_spinbox: SpinBox = replace_cel_options.get_node("AtFrameSpinbox")
|
||||
at_frame_spinbox.max_value = Global.current_project.frames.size()
|
||||
|
||||
elif id == ImageImportOptions.NEW_LAYER:
|
||||
|
|
|
@ -161,40 +161,40 @@ margin_right = 53.0
|
|||
margin_bottom = 19.0
|
||||
text = "At layer:"
|
||||
|
||||
[node name="AtLayerSpinbox" type="SpinBox" parent="VBoxContainer/HBoxContainer/NewFrameOptions"]
|
||||
[node name="AtLayerOption" type="OptionButton" parent="VBoxContainer/HBoxContainer/NewFrameOptions"]
|
||||
margin_left = 57.0
|
||||
margin_right = 131.0
|
||||
margin_bottom = 24.0
|
||||
margin_right = 86.0
|
||||
margin_bottom = 20.0
|
||||
mouse_default_cursor_shape = 2
|
||||
max_value = 0.0
|
||||
align = 2
|
||||
|
||||
[node name="ReplaceFrameOptions" type="HBoxContainer" parent="VBoxContainer/HBoxContainer"]
|
||||
[node name="ReplaceCelOptions" type="HBoxContainer" parent="VBoxContainer/HBoxContainer"]
|
||||
visible = false
|
||||
margin_left = 155.0
|
||||
margin_right = 427.0
|
||||
margin_bottom = 24.0
|
||||
|
||||
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/ReplaceFrameOptions"]
|
||||
[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer/ReplaceCelOptions"]
|
||||
margin_top = 5.0
|
||||
margin_right = 53.0
|
||||
margin_bottom = 19.0
|
||||
text = "At layer:"
|
||||
|
||||
[node name="AtLayerSpinbox" type="SpinBox" parent="VBoxContainer/HBoxContainer/ReplaceFrameOptions"]
|
||||
[node name="AtLayerOption" type="OptionButton" parent="VBoxContainer/HBoxContainer/ReplaceCelOptions"]
|
||||
margin_left = 57.0
|
||||
margin_right = 131.0
|
||||
margin_bottom = 24.0
|
||||
margin_right = 86.0
|
||||
margin_bottom = 20.0
|
||||
mouse_default_cursor_shape = 2
|
||||
max_value = 0.0
|
||||
align = 2
|
||||
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/HBoxContainer/ReplaceFrameOptions"]
|
||||
[node name="Label2" type="Label" parent="VBoxContainer/HBoxContainer/ReplaceCelOptions"]
|
||||
margin_left = 135.0
|
||||
margin_top = 5.0
|
||||
margin_right = 194.0
|
||||
margin_bottom = 19.0
|
||||
text = "At frame:"
|
||||
|
||||
[node name="AtFrameSpinbox" type="SpinBox" parent="VBoxContainer/HBoxContainer/ReplaceFrameOptions"]
|
||||
[node name="AtFrameSpinbox" type="SpinBox" parent="VBoxContainer/HBoxContainer/ReplaceCelOptions"]
|
||||
margin_left = 198.0
|
||||
margin_right = 272.0
|
||||
margin_bottom = 24.0
|
||||
|
|
|
@ -12,6 +12,8 @@ var max_cel_size := 144
|
|||
var past_above_canvas := true
|
||||
var future_above_canvas := true
|
||||
|
||||
var frame_button_node = preload("res://src/UI/Timeline/FrameButton.tscn")
|
||||
|
||||
onready var old_scroll: int = 0 # The previous scroll state of $ScrollContainer
|
||||
onready var tag_spacer = find_node("TagSpacer")
|
||||
onready var start_spacer = find_node("StartSpacer")
|
||||
|
@ -23,6 +25,7 @@ onready var tag_scroll_container: ScrollContainer = find_node("TagScroll")
|
|||
onready var fps_spinbox: SpinBox = find_node("FPSValue")
|
||||
onready var onion_skinning_button: BaseButton = find_node("OnionSkinning")
|
||||
onready var loop_animation_button: BaseButton = find_node("LoopAnim")
|
||||
onready var drag_highlight: ColorRect = find_node("DragHighlight")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
@ -36,6 +39,11 @@ func _ready() -> void:
|
|||
timeline_scroll.size_flags_horizontal = SIZE_FILL
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_DRAG_END:
|
||||
drag_highlight.hide()
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
var mouse_pos := get_global_mouse_position()
|
||||
var timeline_rect := Rect2(rect_global_position, rect_size)
|
||||
|
@ -125,18 +133,16 @@ func add_frame() -> void:
|
|||
var project: Project = Global.current_project
|
||||
var frame_add_index := project.current_frame + 1
|
||||
var frame: Frame = project.new_empty_frame()
|
||||
var new_frames: Array = project.frames.duplicate()
|
||||
var new_layers: Array = project.duplicate_layers()
|
||||
new_frames.insert(frame_add_index, frame)
|
||||
|
||||
for l_i in range(new_layers.size()):
|
||||
if new_layers[l_i].new_cels_linked: # If the link button is pressed
|
||||
if new_layers[l_i].get("new_cels_linked"): # If the link button is pressed
|
||||
new_layers[l_i].linked_cels.append(frame)
|
||||
frame.cels[l_i].image = new_layers[l_i].linked_cels[0].cels[l_i].image
|
||||
frame.cels[l_i].set_content(new_layers[l_i].linked_cels[0].cels[l_i].get_content())
|
||||
frame.cels[l_i].image_texture = new_layers[l_i].linked_cels[0].cels[l_i].image_texture
|
||||
|
||||
# Code to PUSH AHEAD tags starting after the frame
|
||||
var new_animation_tags := Global.current_project.animation_tags.duplicate()
|
||||
var new_animation_tags := project.animation_tags.duplicate()
|
||||
# Loop through the tags to create new classes for them, so that they won't be the same
|
||||
# as Global.current_project.animation_tags's classes. Needed for undo/redo to work properly.
|
||||
for i in new_animation_tags.size():
|
||||
|
@ -158,46 +164,43 @@ func add_frame() -> void:
|
|||
project.undo_redo.create_action("Add Frame")
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
|
||||
project.undo_redo.add_do_property(project, "frames", new_frames)
|
||||
project.undo_redo.add_do_property(project, "current_frame", project.current_frame + 1)
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "animation_tags", new_animation_tags
|
||||
)
|
||||
project.undo_redo.add_do_property(project, "layers", new_layers)
|
||||
|
||||
project.undo_redo.add_undo_property(project, "frames", project.frames)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "animation_tags", Global.current_project.animation_tags
|
||||
)
|
||||
project.undo_redo.add_undo_property(project, "layers", project.layers)
|
||||
project.undo_redo.add_do_method(project, "add_frames", [frame], [frame_add_index])
|
||||
project.undo_redo.add_undo_method(project, "remove_frames", [frame_add_index])
|
||||
project.undo_redo.add_do_property(project, "animation_tags", new_animation_tags)
|
||||
project.undo_redo.add_undo_property(project, "animation_tags", project.animation_tags)
|
||||
project.undo_redo.add_do_property(project, "current_frame", project.current_frame + 1)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_DeleteFrame_pressed(frame := -1) -> void:
|
||||
var frames := []
|
||||
func _on_DeleteFrame_pressed() -> void:
|
||||
var indices := []
|
||||
for cel in Global.current_project.selected_cels:
|
||||
frame = cel[0]
|
||||
if not frame in frames:
|
||||
frames.append(frame)
|
||||
frames.sort()
|
||||
delete_frames(frames)
|
||||
var f: int = cel[0]
|
||||
if not f in indices:
|
||||
indices.append(f)
|
||||
indices.sort()
|
||||
delete_frames(indices)
|
||||
|
||||
|
||||
func delete_frames(frames := []) -> void:
|
||||
if Global.current_project.frames.size() == 1:
|
||||
func delete_frames(indices := []) -> void:
|
||||
var project: Project = Global.current_project
|
||||
if project.frames.size() == 1:
|
||||
return
|
||||
|
||||
if frames.size() == 0:
|
||||
frames.append(Global.current_project.current_frame)
|
||||
if indices.size() == project.frames.size():
|
||||
indices.remove(indices.size() - 1) # Ensure the project has at least 1 frame
|
||||
elif indices.size() == 0:
|
||||
indices.append(project.current_frame)
|
||||
|
||||
var new_frames: Array = Global.current_project.frames.duplicate()
|
||||
var current_frame := Global.current_project.current_frame
|
||||
var new_layers: Array = Global.current_project.duplicate_layers()
|
||||
var current_frame: int = min(project.current_frame, project.frames.size() - indices.size() - 1)
|
||||
var new_layers: Array = project.duplicate_layers()
|
||||
var frames := []
|
||||
var frame_correction := 0 # Only needed for tag adjustment
|
||||
|
||||
var new_animation_tags := Global.current_project.animation_tags.duplicate()
|
||||
var new_animation_tags := project.animation_tags.duplicate()
|
||||
# Loop through the tags to create new classes for them, so that they won't be the same
|
||||
# as Global.current_project.animation_tags's classes. Needed for undo/redo to work properly.
|
||||
for i in new_animation_tags.size():
|
||||
|
@ -208,90 +211,70 @@ func delete_frames(frames := []) -> void:
|
|||
new_animation_tags[i].to
|
||||
)
|
||||
|
||||
for frame in frames:
|
||||
if new_frames.size() == 1: # If only 1 frame
|
||||
break
|
||||
var frame_to_delete: Frame = Global.current_project.frames[frame]
|
||||
new_frames.erase(frame_to_delete)
|
||||
if current_frame > 0 && current_frame == new_frames.size(): # If it's the last frame
|
||||
current_frame -= 1
|
||||
|
||||
for f in indices:
|
||||
frames.append(project.frames[f])
|
||||
# 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
|
||||
for layer in new_layers:
|
||||
for linked in layer.linked_cels:
|
||||
if linked == Global.current_project.frames[frame]:
|
||||
if linked == project.frames[f]:
|
||||
layer.linked_cels.erase(linked)
|
||||
|
||||
# Loop through the tags to see if the frame is in one
|
||||
frame -= frame_correction # Erasing made frames indexes 1 step ahead their intended tags
|
||||
f -= frame_correction # Erasing made frames indexes 1 step ahead their intended tags
|
||||
var tag_correction := 0 # needed when tag is erased
|
||||
for tag_ind in new_animation_tags.size():
|
||||
var tag = new_animation_tags[tag_ind - tag_correction]
|
||||
if frame + 1 >= tag.from && frame + 1 <= tag.to:
|
||||
if f + 1 >= tag.from && f + 1 <= tag.to:
|
||||
if tag.from == tag.to: # If we're deleting the only frame in the tag
|
||||
new_animation_tags.erase(tag)
|
||||
tag_correction += 1
|
||||
else:
|
||||
tag.to -= 1
|
||||
elif frame + 1 < tag.from:
|
||||
elif f + 1 < tag.from:
|
||||
tag.from -= 1
|
||||
tag.to -= 1
|
||||
frame_correction += 1 # Compensation for the next batch
|
||||
|
||||
Global.current_project.undos += 1
|
||||
Global.current_project.undo_redo.create_action("Remove Frame")
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "frames", new_frames)
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", current_frame
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "animation_tags", new_animation_tags
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "frames", Global.current_project.frames
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_frame", Global.current_project.current_frame
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "animation_tags", Global.current_project.animation_tags
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Remove Frame")
|
||||
project.undo_redo.add_do_property(project, "layers", new_layers)
|
||||
project.undo_redo.add_undo_property(project, "layers", Global.current_project.layers)
|
||||
project.undo_redo.add_do_method(project, "remove_frames", indices)
|
||||
project.undo_redo.add_undo_method(project, "add_frames", frames, indices)
|
||||
project.undo_redo.add_do_property(project, "animation_tags", new_animation_tags)
|
||||
project.undo_redo.add_undo_property(project, "animation_tags", project.animation_tags)
|
||||
project.undo_redo.add_do_property(project, "current_frame", current_frame)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_CopyFrame_pressed(frame := -1) -> void:
|
||||
var frames := []
|
||||
func _on_CopyFrame_pressed() -> void:
|
||||
var indices := []
|
||||
for cel in Global.current_project.selected_cels:
|
||||
frame = cel[0]
|
||||
if not frame in frames:
|
||||
frames.append(frame)
|
||||
frames.sort()
|
||||
copy_frames(frames)
|
||||
var f: int = cel[0]
|
||||
if not f in indices:
|
||||
indices.append(f)
|
||||
indices.sort()
|
||||
copy_frames(indices)
|
||||
|
||||
|
||||
func copy_frames(frames := []) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
func copy_frames(indices := []) -> void:
|
||||
var project: Project = Global.current_project
|
||||
|
||||
if frames.size() == 0:
|
||||
frames.append(Global.current_project.current_frame)
|
||||
if indices.size() == 0:
|
||||
indices.append(project.current_frame)
|
||||
|
||||
var new_frames := Global.current_project.frames.duplicate()
|
||||
var new_layers: Array = Global.current_project.duplicate_layers()
|
||||
var new_layers: Array = project.duplicate_layers()
|
||||
var copied_frames := []
|
||||
var copied_indices := range(indices[-1] + 1, indices[-1] + 1 + indices.size())
|
||||
|
||||
var new_animation_tags := Global.current_project.animation_tags.duplicate()
|
||||
var new_animation_tags := project.animation_tags.duplicate()
|
||||
# Loop through the tags to create new classes for them, so that they won't be the same
|
||||
# as Global.current_project.animation_tags's classes. Needed for undo/redo to work properly.
|
||||
# as project.animation_tags's classes. Needed for undo/redo to work properly.
|
||||
for i in new_animation_tags.size():
|
||||
new_animation_tags[i] = AnimationTag.new(
|
||||
new_animation_tags[i].name,
|
||||
|
@ -300,61 +283,48 @@ func copy_frames(frames := []) -> void:
|
|||
new_animation_tags[i].to
|
||||
)
|
||||
|
||||
for frm in frames.size():
|
||||
var frame = frames[(frames.size() - 1) - frm]
|
||||
for f in indices:
|
||||
var new_frame := Frame.new()
|
||||
new_frames.insert(frames[-1] + 1, new_frame)
|
||||
copied_frames.append(new_frame)
|
||||
|
||||
var prev_frame: Frame = Global.current_project.frames[frame]
|
||||
for cel in prev_frame.cels: # Copy every cel
|
||||
var sprite := Image.new()
|
||||
sprite.copy_from(cel.image)
|
||||
var sprite_texture := ImageTexture.new()
|
||||
sprite_texture.create_from_image(sprite, 0)
|
||||
new_frame.cels.append(Cel.new(sprite, cel.opacity, sprite_texture))
|
||||
var prev_frame: Frame = project.frames[f]
|
||||
|
||||
new_frame.duration = prev_frame.duration
|
||||
for l_i in range(new_layers.size()):
|
||||
if new_layers[l_i].new_cels_linked: # If the link button is pressed
|
||||
# If the layer has new_cels_linked variable, and its true
|
||||
var new_cels_linked := true if new_layers[l_i].get("new_cels_linked") else false
|
||||
|
||||
# Copy the cel, create new cel content if new cels aren't linked
|
||||
new_frame.cels.append(new_layers[l_i].copy_cel(f, new_cels_linked))
|
||||
|
||||
if new_cels_linked: # If the link button is pressed
|
||||
new_layers[l_i].linked_cels.append(new_frame)
|
||||
new_frame.cels[l_i].image = new_layers[l_i].linked_cels[0].cels[l_i].image
|
||||
new_frame.cels[l_i].set_content(
|
||||
new_layers[l_i].linked_cels[0].cels[l_i].get_content()
|
||||
)
|
||||
new_frame.cels[l_i].image_texture = new_layers[l_i].linked_cels[0].cels[l_i].image_texture
|
||||
|
||||
# Loop through the tags to see if the frame is in one
|
||||
for tag in new_animation_tags:
|
||||
if frames[-1] + 1 >= tag.from && frames[-1] + 1 <= tag.to:
|
||||
if indices[-1] + 1 >= tag.from && indices[-1] + 1 <= tag.to:
|
||||
tag.to += 1
|
||||
elif frames[-1] + 1 < tag.from:
|
||||
elif indices[-1] + 1 < tag.from:
|
||||
tag.from += 1
|
||||
tag.to += 1
|
||||
|
||||
Global.current_project.undos += 1
|
||||
Global.current_project.undo_redo.create_action("Add Frame")
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "frames", new_frames)
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", frames[-1] + 1
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "animation_tags", new_animation_tags
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "frames", Global.current_project.frames
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_frame", frames[-1]
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "animation_tags", Global.current_project.animation_tags
|
||||
)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Add Frame")
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_do_property(project, "layers", new_layers)
|
||||
project.undo_redo.add_undo_property(project, "layers", project.layers)
|
||||
project.undo_redo.add_do_method(project, "add_frames", copied_frames, copied_indices)
|
||||
project.undo_redo.add_undo_method(project, "remove_frames", copied_indices)
|
||||
project.undo_redo.add_do_property(project, "current_frame", indices[-1] + 1)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", indices[-1])
|
||||
project.undo_redo.add_do_property(project, "animation_tags", new_animation_tags)
|
||||
project.undo_redo.add_undo_property(project, "animation_tags", project.animation_tags)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_FrameTagButton_pressed() -> void:
|
||||
|
@ -431,9 +401,12 @@ func _on_PlayBackwards_toggled(button_pressed: bool) -> void:
|
|||
play_animation(button_pressed, false)
|
||||
|
||||
|
||||
# Called on each frame of the animation
|
||||
func _on_AnimationTimer_timeout() -> void:
|
||||
if first_frame == last_frame:
|
||||
$AnimationTimer.stop()
|
||||
Global.play_forward.pressed = false
|
||||
Global.play_backwards.pressed = false
|
||||
Global.animation_timer.stop()
|
||||
return
|
||||
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
|
@ -597,202 +570,237 @@ func _on_FuturePlacement_item_selected(index: int) -> void:
|
|||
# Layer buttons
|
||||
|
||||
|
||||
func add_layer(is_new := true) -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
var new_layers: Array = Global.current_project.layers.duplicate()
|
||||
var l := Layer.new()
|
||||
if !is_new: # Clone layer
|
||||
l.name = (
|
||||
Global.current_project.layers[Global.current_project.current_layer].name
|
||||
+ " ("
|
||||
+ tr("copy")
|
||||
+ ")"
|
||||
)
|
||||
new_layers.append(l)
|
||||
func _on_AddLayer_pressed() -> void:
|
||||
var project: Project = Global.current_project
|
||||
|
||||
Global.current_project.undos += 1
|
||||
Global.current_project.undo_redo.create_action("Add Layer")
|
||||
var l := PixelLayer.new(project)
|
||||
var cels := []
|
||||
for f in project.frames:
|
||||
cels.append(l.new_empty_cel())
|
||||
|
||||
for f in Global.current_project.frames:
|
||||
var new_layer := Image.new()
|
||||
if is_new:
|
||||
new_layer.create(
|
||||
Global.current_project.size.x,
|
||||
Global.current_project.size.y,
|
||||
false,
|
||||
Image.FORMAT_RGBA8
|
||||
)
|
||||
else: # Clone layer
|
||||
new_layer.copy_from(f.cels[Global.current_project.current_layer].image)
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Add Layer")
|
||||
project.undo_redo.add_do_property(project, "current_layer", project.layers.size())
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_do_method(project, "add_layers", [l], [project.layers.size()], [cels])
|
||||
project.undo_redo.add_undo_method(project, "remove_layers", [project.layers.size()])
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
var new_cels: Array = f.cels.duplicate()
|
||||
new_cels.append(Cel.new(new_layer, 1))
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_layer", Global.current_project.layers.size()
|
||||
func _on_AddGroup_pressed() -> void:
|
||||
var project: Project = Global.current_project
|
||||
|
||||
var l := GroupLayer.new(project)
|
||||
var cels := []
|
||||
for f in project.frames:
|
||||
cels.append(l.new_empty_cel())
|
||||
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Add Layer")
|
||||
project.undo_redo.add_do_property(project, "current_layer", project.layers.size())
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_do_method(project, "add_layers", [l], [project.layers.size()], [cels])
|
||||
project.undo_redo.add_undo_method(project, "remove_layers", [project.layers.size()])
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_CloneLayer_pressed() -> void:
|
||||
var project: Project = Global.current_project
|
||||
var source_layers: Array = project.layers[project.current_layer].get_children(true)
|
||||
source_layers.append(project.layers[project.current_layer])
|
||||
|
||||
var clones := [] # Array of Layers
|
||||
var cels := [] # 2D Array of Cels
|
||||
for sl in source_layers:
|
||||
var cl: BaseLayer = sl.copy()
|
||||
if sl.index == project.current_layer:
|
||||
cl.name = str(sl.name, " (", tr("copy"), ")")
|
||||
clones.append(cl)
|
||||
cels.append(sl.copy_all_cels())
|
||||
|
||||
# Swap parents with clones if the parent is one of the source layers
|
||||
for cl in clones:
|
||||
var p = source_layers.find(cl.parent)
|
||||
if p > -1:
|
||||
cl.parent = clones[p]
|
||||
|
||||
var indices := range(project.current_layer + 1, project.current_layer + clones.size() + 1)
|
||||
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Add Layer")
|
||||
project.undo_redo.add_do_property(
|
||||
project, "current_layer", project.current_layer + clones.size()
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_do_method(project, "add_layers", clones, indices, cels)
|
||||
project.undo_redo.add_undo_method(project, "remove_layers", indices)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_RemoveLayer_pressed() -> void:
|
||||
if Global.current_project.layers.size() == 1:
|
||||
var project: Project = Global.current_project
|
||||
if project.layers.size() == 1:
|
||||
return
|
||||
var new_layers: Array = Global.current_project.layers.duplicate()
|
||||
new_layers.remove(Global.current_project.current_layer)
|
||||
Global.current_project.undos += 1
|
||||
Global.current_project.undo_redo.create_action("Remove Layer")
|
||||
if Global.current_project.current_layer > 0:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer - 1
|
||||
)
|
||||
else:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
)
|
||||
|
||||
for f in Global.current_project.frames:
|
||||
var new_cels: Array = f.cels.duplicate()
|
||||
new_cels.remove(Global.current_project.current_layer)
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
var layers: Array = project.layers[project.current_layer].get_children(true)
|
||||
layers.append(project.layers[project.current_layer])
|
||||
var indices := []
|
||||
for l in layers:
|
||||
indices.append(l.index)
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
var cels := []
|
||||
for l in layers:
|
||||
cels.append([])
|
||||
for f in project.frames:
|
||||
cels[-1].append(f.cels[l.index])
|
||||
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Remove Layer")
|
||||
project.undo_redo.add_do_property(project, "current_layer", max(indices[0] - 1, 0))
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_do_method(project, "remove_layers", indices)
|
||||
project.undo_redo.add_undo_method(project, "add_layers", layers, indices, cels)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
# Move the layer up or down in layer order and/or reparent to be deeper/shallower in the
|
||||
# layer hierarchy depending on its current index and parent
|
||||
func change_layer_order(up: bool) -> void:
|
||||
var project: Project = Global.current_project
|
||||
var layer: BaseLayer = project.layers[project.current_layer]
|
||||
var child_count = layer.get_child_count(true)
|
||||
var from_indices := range(layer.index - child_count, layer.index + 1)
|
||||
var from_parents := []
|
||||
for l in from_indices:
|
||||
from_parents.append(project.layers[l].parent)
|
||||
var to_parents := from_parents.duplicate()
|
||||
var to_index = layer.index - child_count # the index where the LOWEST shifted layer should end up
|
||||
|
||||
if up:
|
||||
var above_layer: BaseLayer = project.layers[project.current_layer + 1]
|
||||
if layer.parent == above_layer: # Above is the parent, leave the parent and go up
|
||||
to_parents[-1] = above_layer.parent
|
||||
to_index = to_index + 1
|
||||
elif layer.parent != above_layer.parent: # Above layer must be deeper in the hierarchy
|
||||
# Move layer 1 level deeper in hierarchy. Done by setting its parent to the parent of
|
||||
# above_layer, and if that is multiple levels, drop levels until its just 1
|
||||
to_parents[-1] = above_layer.parent
|
||||
while to_parents[-1].parent != layer.parent:
|
||||
to_parents[-1] = to_parents[-1].parent
|
||||
elif above_layer.accepts_child(layer):
|
||||
to_parents[-1] = above_layer
|
||||
else:
|
||||
to_index = to_index + 1
|
||||
else: # Down
|
||||
if layer.index == child_count: # If at the very bottom of the layer stack
|
||||
if not is_instance_valid(layer.parent):
|
||||
return
|
||||
to_parents[-1] = layer.parent.parent # Drop a level in the hierarchy
|
||||
else:
|
||||
var below_layer: BaseLayer = project.layers[project.current_layer - 1 - child_count]
|
||||
if layer.parent != below_layer.parent: # If there is a hierarchy change
|
||||
to_parents[-1] = layer.parent.parent # Drop a level in the hierarchy
|
||||
elif below_layer.accepts_child(layer):
|
||||
to_parents[-1] = below_layer
|
||||
to_index = to_index - 1
|
||||
else:
|
||||
to_index = to_index - 1
|
||||
|
||||
var to_indices := range(to_index, to_index + child_count + 1)
|
||||
|
||||
project.undo_redo.create_action("Change Layer Order")
|
||||
project.undo_redo.add_do_property(project, "current_layer", to_index + child_count)
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_do_method(project, "move_layers", from_indices, to_indices, to_parents)
|
||||
project.undo_redo.add_undo_method(
|
||||
project, "move_layers", to_indices, from_indices, from_parents
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func change_layer_order(rate: int) -> void:
|
||||
var change = Global.current_project.current_layer + rate
|
||||
|
||||
var new_layers: Array = Global.current_project.layers.duplicate()
|
||||
var temp = new_layers[Global.current_project.current_layer]
|
||||
new_layers[Global.current_project.current_layer] = new_layers[change]
|
||||
new_layers[change] = temp
|
||||
Global.current_project.undo_redo.create_action("Change Layer Order")
|
||||
for f in Global.current_project.frames:
|
||||
var new_cels: Array = f.cels.duplicate()
|
||||
var temp_canvas = new_cels[Global.current_project.current_layer]
|
||||
new_cels[Global.current_project.current_layer] = new_cels[change]
|
||||
new_cels[change] = temp_canvas
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_layer", change
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_MergeDownLayer_pressed() -> void:
|
||||
var new_layers: Array = Global.current_project.duplicate_layers()
|
||||
var project: Project = Global.current_project
|
||||
var top_layer: PixelLayer = project.layers[project.current_layer]
|
||||
var bottom_layer: PixelLayer = project.layers[project.current_layer - 1]
|
||||
var new_linked_cels: Array = bottom_layer.linked_cels.duplicate()
|
||||
|
||||
Global.current_project.undos += 1
|
||||
Global.current_project.undo_redo.create_action("Merge Layer")
|
||||
for f in Global.current_project.frames:
|
||||
var new_cels: Array = f.cels.duplicate()
|
||||
for i in new_cels.size():
|
||||
new_cels[i] = Cel.new(new_cels[i].image, new_cels[i].opacity)
|
||||
var selected_layer := Image.new()
|
||||
selected_layer.copy_from(new_cels[Global.current_project.current_layer].image)
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Merge Layer")
|
||||
|
||||
selected_layer.lock()
|
||||
if f.cels[Global.current_project.current_layer].opacity < 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
|
||||
* f.cels[Global.current_project.current_layer].opacity
|
||||
)
|
||||
selected_layer.set_pixel(
|
||||
for f in project.frames:
|
||||
var top_image := Image.new()
|
||||
top_image.copy_from(f.cels[top_layer.index].image)
|
||||
|
||||
top_image.lock()
|
||||
if f.cels[top_layer.index].opacity < 1: # If we have layer transparency
|
||||
for xx in top_image.get_size().x:
|
||||
for yy in top_image.get_size().y:
|
||||
var pixel_color: Color = top_image.get_pixel(xx, yy)
|
||||
var alpha: float = pixel_color.a * f.cels[top_layer.index].opacity
|
||||
top_image.set_pixel(
|
||||
xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)
|
||||
)
|
||||
selected_layer.unlock()
|
||||
top_image.unlock()
|
||||
|
||||
var new_layer := Image.new()
|
||||
new_layer.copy_from(f.cels[Global.current_project.current_layer - 1].image)
|
||||
new_layer.blend_rect(
|
||||
selected_layer, Rect2(Vector2.ZERO, Global.current_project.size), Vector2.ZERO
|
||||
)
|
||||
new_cels.remove(Global.current_project.current_layer)
|
||||
var bottom_image := Image.new()
|
||||
bottom_image.copy_from(f.cels[bottom_layer.index].image)
|
||||
bottom_image.blend_rect(top_image, Rect2(Vector2.ZERO, project.size), Vector2.ZERO)
|
||||
if (
|
||||
!selected_layer.is_invisible()
|
||||
and (
|
||||
Global.current_project.layers[Global.current_project.current_layer - 1].linked_cels.size()
|
||||
> 1
|
||||
)
|
||||
and (
|
||||
f
|
||||
in Global.current_project.layers[(
|
||||
Global.current_project.current_layer
|
||||
- 1
|
||||
)].linked_cels
|
||||
)
|
||||
!top_image.is_invisible()
|
||||
and bottom_layer.linked_cels.size() > 1
|
||||
and f in bottom_layer.linked_cels
|
||||
):
|
||||
new_layers[Global.current_project.current_layer - 1].linked_cels.erase(f)
|
||||
new_cels[Global.current_project.current_layer - 1].image = new_layer
|
||||
new_linked_cels.erase(f)
|
||||
project.undo_redo.add_do_property(
|
||||
f.cels[bottom_layer.index], "image_texture", ImageTexture.new()
|
||||
)
|
||||
project.undo_redo.add_undo_property(
|
||||
f.cels[bottom_layer.index],
|
||||
"image_texture",
|
||||
f.cels[bottom_layer.index].image_texture
|
||||
)
|
||||
project.undo_redo.add_do_property(f.cels[bottom_layer.index], "image", bottom_image)
|
||||
project.undo_redo.add_undo_property(
|
||||
f.cels[bottom_layer.index], "image", f.cels[bottom_layer.index].image
|
||||
)
|
||||
else:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
f.cels[Global.current_project.current_layer - 1].image, "data", new_layer.data
|
||||
project.undo_redo.add_do_property(
|
||||
f.cels[bottom_layer.index].image, "data", bottom_image.data
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
f.cels[Global.current_project.current_layer - 1].image,
|
||||
"data",
|
||||
f.cels[Global.current_project.current_layer - 1].image.data
|
||||
project.undo_redo.add_undo_property(
|
||||
f.cels[bottom_layer.index].image, "data", f.cels[bottom_layer.index].image.data
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
var top_cels := []
|
||||
for f in project.frames:
|
||||
top_cels.append(f.cels[top_layer.index])
|
||||
|
||||
new_layers.remove(Global.current_project.current_layer)
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer - 1
|
||||
project.undo_redo.add_do_property(project, "current_layer", bottom_layer.index)
|
||||
project.undo_redo.add_undo_property(project, "current_layer", top_layer.index)
|
||||
project.undo_redo.add_do_property(bottom_layer, "linked_cels", new_linked_cels)
|
||||
project.undo_redo.add_undo_property(bottom_layer, "linked_cels", bottom_layer.linked_cels)
|
||||
project.undo_redo.add_do_method(project, "remove_layers", [top_layer.index])
|
||||
project.undo_redo.add_undo_method(
|
||||
project, "add_layers", [top_layer], [top_layer.index], [top_cels]
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _on_OpacitySlider_value_changed(value) -> void:
|
||||
var current_frame: Frame = Global.current_project.frames[Global.current_project.current_frame]
|
||||
var cel: Cel = current_frame.cels[Global.current_project.current_layer]
|
||||
var cel: BaseCel = current_frame.cels[Global.current_project.current_layer]
|
||||
cel.opacity = value / 100
|
||||
Global.layer_opacity_slider.value = value
|
||||
Global.layer_opacity_spinbox.value = value
|
||||
|
@ -801,3 +809,117 @@ func _on_OpacitySlider_value_changed(value) -> void:
|
|||
|
||||
func _on_OnionSkinningSettings_popup_hide() -> void:
|
||||
Global.can_draw = true
|
||||
|
||||
|
||||
# Methods to update the UI in response to changes in the current project
|
||||
|
||||
|
||||
func project_changed() -> void:
|
||||
var project: Project = Global.current_project
|
||||
# These must be removed from tree immediately to not mess up the indices of
|
||||
# the new buttons, so use either free or queue_free + parent.remove_child
|
||||
for child in Global.layers_container.get_children():
|
||||
child.free()
|
||||
for child in Global.frame_ids.get_children():
|
||||
child.free()
|
||||
for container in Global.frames_container.get_children():
|
||||
container.free()
|
||||
|
||||
for i in project.layers.size():
|
||||
project_layer_added(i)
|
||||
for f in project.frames.size():
|
||||
var button: Button = frame_button_node.instance()
|
||||
button.frame = f
|
||||
Global.frame_ids.add_child(button)
|
||||
|
||||
# Press selected cel/frame/layer buttons
|
||||
for cel in project.selected_cels:
|
||||
var frame: int = cel[0]
|
||||
var layer: int = cel[1]
|
||||
if frame < Global.frame_ids.get_child_count():
|
||||
var frame_button: BaseButton = Global.frame_ids.get_child(frame)
|
||||
frame_button.pressed = true
|
||||
|
||||
var container_child_count: int = Global.frames_container.get_child_count()
|
||||
if layer < container_child_count:
|
||||
var container = Global.frames_container.get_child(container_child_count - 1 - layer)
|
||||
if frame < container.get_child_count():
|
||||
var cel_button = container.get_child(frame)
|
||||
cel_button.pressed = true
|
||||
|
||||
var layer_button = Global.layers_container.get_child(container_child_count - 1 - layer)
|
||||
layer_button.pressed = true
|
||||
|
||||
|
||||
func project_frame_added(frame: int) -> void:
|
||||
var project: Project = Global.current_project
|
||||
var button: Button = frame_button_node.instance()
|
||||
button.frame = frame
|
||||
Global.frame_ids.add_child(button)
|
||||
Global.frame_ids.move_child(button, frame)
|
||||
|
||||
var layer := Global.frames_container.get_child_count() - 1
|
||||
for container in Global.frames_container.get_children():
|
||||
var cel_button = project.frames[frame].cels[layer].instantiate_cel_button()
|
||||
cel_button.frame = frame
|
||||
cel_button.layer = layer
|
||||
container.add_child(cel_button)
|
||||
container.move_child(cel_button, frame)
|
||||
layer -= 1
|
||||
|
||||
|
||||
func project_frame_removed(frame: int) -> void:
|
||||
Global.frame_ids.get_child(frame).queue_free()
|
||||
Global.frame_ids.remove_child(Global.frame_ids.get_child(frame))
|
||||
for container in Global.frames_container.get_children():
|
||||
container.get_child(frame).free()
|
||||
|
||||
|
||||
func project_layer_added(layer: int) -> void:
|
||||
var project: Project = Global.current_project
|
||||
|
||||
var layer_button: LayerButton = project.layers[layer].instantiate_layer_button()
|
||||
layer_button.layer = layer
|
||||
if project.layers[layer].name == "":
|
||||
project.layers[layer].set_name_to_default(layer)
|
||||
|
||||
var layer_cel_container := HBoxContainer.new()
|
||||
for f in project.frames.size():
|
||||
var cel_button = project.frames[f].cels[layer].instantiate_cel_button()
|
||||
cel_button.frame = f
|
||||
cel_button.layer = layer
|
||||
layer_cel_container.add_child(cel_button)
|
||||
|
||||
layer_button.visible = Global.current_project.layers[layer].is_expanded_in_hierarchy()
|
||||
layer_cel_container.visible = layer_button.visible
|
||||
|
||||
Global.layers_container.add_child(layer_button)
|
||||
var count := Global.layers_container.get_child_count()
|
||||
Global.layers_container.move_child(layer_button, count - 1 - layer)
|
||||
Global.frames_container.add_child(layer_cel_container)
|
||||
Global.frames_container.move_child(layer_cel_container, count - 1 - layer)
|
||||
|
||||
|
||||
func project_layer_removed(layer: int) -> void:
|
||||
var count := Global.layers_container.get_child_count()
|
||||
Global.layers_container.get_child(count - 1 - layer).free()
|
||||
Global.frames_container.get_child(count - 1 - layer).free()
|
||||
|
||||
|
||||
func project_cel_added(frame: int, layer: int) -> void:
|
||||
var container := Global.frames_container.get_child(
|
||||
Global.frames_container.get_child_count() - 1 - layer
|
||||
)
|
||||
var cel_button = Global.current_project.frames[frame].cels[layer].instantiate_cel_button()
|
||||
cel_button.frame = frame
|
||||
cel_button.layer = layer
|
||||
container.add_child(cel_button)
|
||||
container.move_child(cel_button, frame)
|
||||
|
||||
|
||||
func project_cel_removed(frame: int, layer: int) -> void:
|
||||
var container := Global.frames_container.get_child(
|
||||
Global.frames_container.get_child_count() - 1 - layer
|
||||
)
|
||||
container.get_child(frame).queue_free()
|
||||
container.remove_child(container.get_child(frame))
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
[ext_resource path="res://assets/graphics/layers/delete.png" type="Texture" id=6]
|
||||
[ext_resource path="res://assets/graphics/layers/clone.png" type="Texture" id=7]
|
||||
[ext_resource path="res://assets/graphics/timeline/move_arrow.png" type="Texture" id=8]
|
||||
[ext_resource path="res://src/UI/Timeline/FrameButton.tscn" type="PackedScene" id=9]
|
||||
[ext_resource path="res://assets/graphics/layers/group_new.png" type="Texture" id=10]
|
||||
[ext_resource path="res://assets/graphics/timeline/new_frame.png" type="Texture" id=19]
|
||||
[ext_resource path="res://assets/graphics/timeline/remove_frame.png" type="Texture" id=20]
|
||||
[ext_resource path="res://assets/graphics/timeline/go_to_first_frame.png" type="Texture" id=21]
|
||||
|
@ -99,14 +99,17 @@ margin_bottom = 160.0
|
|||
rect_min_size = Vector2( 36, 160 )
|
||||
rect_clip_content = true
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="TimelineContainer" type="VBoxContainer" parent="ScrollContainer"]
|
||||
margin_right = 902.0
|
||||
margin_bottom = 160.0
|
||||
margin_right = 745.0
|
||||
margin_bottom = 104.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
__meta__ = {
|
||||
|
@ -119,14 +122,15 @@ margin_bottom = 38.0
|
|||
size_flags_horizontal = 3
|
||||
|
||||
[node name="LayerButtonPanelContainer" type="PanelContainer" parent="ScrollContainer/TimelineContainer/TimelineButtons"]
|
||||
margin_right = 186.0
|
||||
margin_right = 190.0
|
||||
margin_bottom = 38.0
|
||||
rect_min_size = Vector2( 190, 0 )
|
||||
custom_styles/panel = SubResource( 2 )
|
||||
|
||||
[node name="LayerButtons" type="HBoxContainer" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer"]
|
||||
margin_left = 4.5
|
||||
margin_top = 3.0
|
||||
margin_right = 181.5
|
||||
margin_right = 185.5
|
||||
margin_bottom = 25.0
|
||||
size_flags_vertical = 0
|
||||
custom_constants/separation = 9
|
||||
|
@ -155,11 +159,36 @@ __meta__ = {
|
|||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="RemoveLayer" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
[node name="AddGroup" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 31.0
|
||||
margin_right = 53.0
|
||||
margin_bottom = 22.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Create a new group layer"
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/AddGroup"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -11.0
|
||||
margin_top = -11.0
|
||||
margin_right = 11.0
|
||||
margin_bottom = 11.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
texture = ExtResource( 10 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="RemoveLayer" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 62.0
|
||||
margin_right = 84.0
|
||||
margin_bottom = 22.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Remove current layer"
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 8
|
||||
|
@ -182,8 +211,8 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="MoveUpLayer" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 62.0
|
||||
margin_right = 84.0
|
||||
margin_left = 93.0
|
||||
margin_right = 115.0
|
||||
margin_bottom = 22.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Move up the current layer"
|
||||
|
@ -208,8 +237,8 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="MoveDownLayer" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 93.0
|
||||
margin_right = 115.0
|
||||
margin_left = 124.0
|
||||
margin_right = 146.0
|
||||
margin_bottom = 22.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Move down the current layer"
|
||||
|
@ -234,8 +263,8 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="CloneLayer" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 124.0
|
||||
margin_right = 146.0
|
||||
margin_left = 155.0
|
||||
margin_right = 177.0
|
||||
margin_bottom = 22.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Clone current layer"
|
||||
|
@ -259,8 +288,8 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="MergeDownLayer" type="Button" parent="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 155.0
|
||||
margin_right = 177.0
|
||||
margin_left = 186.0
|
||||
margin_right = 208.0
|
||||
margin_bottom = 22.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Merge current layer with the one below"
|
||||
|
@ -285,8 +314,8 @@ __meta__ = {
|
|||
}
|
||||
|
||||
[node name="Control" type="Control" parent="ScrollContainer/TimelineContainer/TimelineButtons"]
|
||||
margin_left = 190.0
|
||||
margin_right = 378.0
|
||||
margin_left = 194.0
|
||||
margin_right = 386.0
|
||||
margin_bottom = 38.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
|
@ -783,12 +812,12 @@ align = 1
|
|||
|
||||
[node name="SpacerControl2" type="Control" parent="ScrollContainer/TimelineContainer/OpacityAndTagContainer"]
|
||||
margin_left = 188.0
|
||||
margin_right = 217.0
|
||||
margin_right = 240.0
|
||||
margin_bottom = 32.0
|
||||
rect_min_size = Vector2( 29, 0 )
|
||||
rect_min_size = Vector2( 52, 32 )
|
||||
|
||||
[node name="TagScroll" type="ScrollContainer" parent="ScrollContainer/TimelineContainer/OpacityAndTagContainer"]
|
||||
margin_left = 219.0
|
||||
margin_left = 242.0
|
||||
margin_right = 902.0
|
||||
margin_bottom = 32.0
|
||||
rect_min_size = Vector2( 0, 32 )
|
||||
|
@ -798,7 +827,6 @@ theme = SubResource( 20 )
|
|||
scroll_vertical_enabled = false
|
||||
|
||||
[node name="HBoxContainer" type="HBoxContainer" parent="ScrollContainer/TimelineContainer/OpacityAndTagContainer/TagScroll"]
|
||||
margin_right = 683.0
|
||||
margin_bottom = 32.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
@ -808,7 +836,7 @@ custom_constants/separation = 0
|
|||
margin_bottom = 32.0
|
||||
|
||||
[node name="TagContainer" type="Control" parent="ScrollContainer/TimelineContainer/OpacityAndTagContainer/TagScroll/HBoxContainer"]
|
||||
margin_right = 683.0
|
||||
margin_right = 660.0
|
||||
margin_bottom = 32.0
|
||||
size_flags_horizontal = 3
|
||||
|
||||
|
@ -835,8 +863,8 @@ margin_bottom = 68.0
|
|||
size_flags_horizontal = 3
|
||||
|
||||
[node name="LayersAndFrames" type="HBoxContainer" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer/TimelineScroll"]
|
||||
margin_right = 81.0
|
||||
margin_bottom = 68.0
|
||||
margin_right = 45.0
|
||||
margin_bottom = 20.0
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="LayerVBoxCont" type="VBoxContainer" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer/TimelineScroll/LayersAndFrames"]
|
||||
|
@ -858,22 +886,16 @@ margin_bottom = 20.0
|
|||
|
||||
[node name="FrameButtonsAndIds" type="VBoxContainer" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer/TimelineScroll/LayersAndFrames"]
|
||||
margin_left = 45.0
|
||||
margin_right = 81.0
|
||||
margin_right = 45.0
|
||||
margin_bottom = 68.0
|
||||
|
||||
[node name="FrameIDs" type="HBoxContainer" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer/TimelineScroll/LayersAndFrames/FrameButtonsAndIds"]
|
||||
margin_right = 36.0
|
||||
margin_bottom = 20.0
|
||||
margin_bottom = 16.0
|
||||
rect_min_size = Vector2( 0, 16 )
|
||||
|
||||
[node name="FrameButton" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer/TimelineScroll/LayersAndFrames/FrameButtonsAndIds/FrameIDs" instance=ExtResource( 9 )]
|
||||
margin_right = 36.0
|
||||
rect_min_size = Vector2( 36, 0 )
|
||||
|
||||
[node name="FramesContainer" type="VBoxContainer" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer/TimelineScroll/LayersAndFrames/FrameButtonsAndIds"]
|
||||
margin_top = 24.0
|
||||
margin_right = 36.0
|
||||
margin_bottom = 24.0
|
||||
margin_top = 20.0
|
||||
margin_bottom = 20.0
|
||||
|
||||
[node name="EndSpacer" type="Control" parent="ScrollContainer/TimelineContainer/PanelContainer/HBoxContainer"]
|
||||
margin_left = 888.0
|
||||
|
@ -994,13 +1016,21 @@ autowrap = true
|
|||
|
||||
[node name="FrameTagDialog" parent="." instance=ExtResource( 42 )]
|
||||
|
||||
[node name="DragHighlight" type="ColorRect" parent="."]
|
||||
visible = false
|
||||
margin_right = 40.0
|
||||
margin_bottom = 40.0
|
||||
mouse_filter = 2
|
||||
color = Color( 0, 0.741176, 1, 0.501961 )
|
||||
|
||||
[connection signal="item_rect_changed" from="." to="." method="_on_AnimationTimeline_item_rect_changed"]
|
||||
[connection signal="item_rect_changed" from="ScrollContainer/TimelineContainer" to="." method="_on_TimelineContainer_item_rect_changed"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/AddLayer" to="." method="add_layer" binds= [ true ]]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/AddLayer" to="." method="_on_AddLayer_pressed"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/AddGroup" to="." method="_on_AddGroup_pressed"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/RemoveLayer" to="." method="_on_RemoveLayer_pressed"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/MoveUpLayer" to="." method="change_layer_order" binds= [ 1 ]]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/MoveDownLayer" to="." method="change_layer_order" binds= [ -1 ]]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/CloneLayer" to="." method="add_layer" binds= [ false ]]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/MoveUpLayer" to="." method="change_layer_order" binds= [ true ]]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/MoveDownLayer" to="." method="change_layer_order" binds= [ false ]]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/CloneLayer" to="." method="_on_CloneLayer_pressed"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/LayerButtonPanelContainer/LayerButtons/MergeDownLayer" to="." method="_on_MergeDownLayer_pressed"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/PanelContainer/AnimationButtons/FrameButtons/AddFrame" to="." method="add_frame"]
|
||||
[connection signal="pressed" from="ScrollContainer/TimelineContainer/TimelineButtons/PanelContainer/AnimationButtons/FrameButtons/DeleteFrame" to="." method="_on_DeleteFrame_pressed"]
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Timeline/CelButton.gd" type="Script" id=1]
|
||||
[ext_resource path="res://src/Shaders/TransparentChecker.shader" type="Shader" id=1]
|
||||
[ext_resource path="res://src/UI/TransparentChecker.tscn" type="PackedScene" id=2]
|
||||
[ext_resource path="res://src/Shaders/TransparentChecker.shader" type="Shader" id=3]
|
||||
|
||||
[sub_resource type="ShaderMaterial" id=1]
|
||||
shader = ExtResource( 3 )
|
||||
shader = ExtResource( 1 )
|
||||
shader_param/size = 10.0
|
||||
shader_param/alpha = 1.0
|
||||
shader_param/color1 = Color( 0.7, 0.7, 0.7, 1 )
|
||||
|
@ -16,17 +15,18 @@ shader_param/rect_size = Vector2( 0, 0 )
|
|||
shader_param/follow_movement = false
|
||||
shader_param/follow_scale = false
|
||||
|
||||
[node name="CelButton" type="Button"]
|
||||
[node name="BaseCelButton" type="Button"]
|
||||
margin_top = 18.0
|
||||
margin_right = 36.0
|
||||
margin_bottom = 54.0
|
||||
rect_min_size = Vector2( 36, 36 )
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
toggle_mode = true
|
||||
button_mask = 7
|
||||
script = ExtResource( 1 )
|
||||
enabled_focus_mode = 0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
@ -53,21 +53,5 @@ anchor_bottom = 1.0
|
|||
margin_right = 0.0
|
||||
margin_bottom = 0.0
|
||||
|
||||
[node name="PopupMenu" type="PopupMenu" parent="."]
|
||||
margin_right = 20.0
|
||||
margin_bottom = 20.0
|
||||
mouse_default_cursor_shape = 2
|
||||
items = [ "Delete", null, 0, false, false, -1, 0, null, "", false, "Link Cel", null, 0, false, false, -1, 0, null, "", false ]
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LinkedIndicator" type="Polygon2D" parent="."]
|
||||
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="resized" from="." to="." method="_on_CelButton_resized"]
|
||||
[connection signal="id_pressed" from="PopupMenu" to="." method="_on_PopupMenu_id_pressed"]
|
|
@ -1,18 +1,19 @@
|
|||
[gd_scene load_steps=5 format=2]
|
||||
[gd_scene load_steps=4 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Timeline/LayerButton.gd" type="Script" id=1]
|
||||
[ext_resource path="res://assets/graphics/layers/layer_visible.png" type="Texture" id=2]
|
||||
[ext_resource path="res://assets/graphics/layers/unlock.png" type="Texture" id=3]
|
||||
[ext_resource path="res://assets/graphics/layers/unlinked_layer.png" type="Texture" id=4]
|
||||
|
||||
[node name="LayerContainer" type="Button"]
|
||||
margin_right = 210.0
|
||||
[node name="BaseLayerButton" type="Button"]
|
||||
margin_right = 236.0
|
||||
margin_bottom = 36.0
|
||||
rect_min_size = Vector2( 212, 36 )
|
||||
rect_min_size = Vector2( 236, 36 )
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 0
|
||||
toggle_mode = true
|
||||
action_mode = 0
|
||||
enabled_focus_mode = 0
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
"_edit_horizontal_guides_": [ ],
|
||||
|
@ -29,6 +30,7 @@ __meta__ = {
|
|||
|
||||
[node name="EmptySpacer" type="Control" parent="HBoxContainer"]
|
||||
margin_bottom = 36.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="LayerButtons" type="HBoxContainer" parent="HBoxContainer"]
|
||||
margin_left = 4.0
|
||||
|
@ -36,11 +38,37 @@ margin_right = 90.0
|
|||
margin_bottom = 36.0
|
||||
custom_constants/separation = 10
|
||||
|
||||
[node name="VisibilityButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
|
||||
[node name="ExpandButton" type="ToolButton" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_top = 7.0
|
||||
margin_right = 22.0
|
||||
margin_bottom = 29.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Expand/collapse group"
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 4
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/ExpandButton"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -11.0
|
||||
margin_top = -11.0
|
||||
margin_right = 11.0
|
||||
margin_bottom = 11.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="VisibilityButton" type="ToolButton" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 32.0
|
||||
margin_top = 7.0
|
||||
margin_right = 54.0
|
||||
margin_bottom = 29.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Toggle layer's visibility"
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
|
@ -63,10 +91,10 @@ __meta__ = {
|
|||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LockButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 32.0
|
||||
[node name="LockButton" type="ToolButton" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 64.0
|
||||
margin_top = 7.0
|
||||
margin_right = 54.0
|
||||
margin_right = 86.0
|
||||
margin_bottom = 29.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Lock/unlock layer"
|
||||
|
@ -91,72 +119,53 @@ __meta__ = {
|
|||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LinkButton" type="Button" parent="HBoxContainer/LayerButtons" groups=["UIButtons"]]
|
||||
margin_left = 64.0
|
||||
margin_top = 7.0
|
||||
margin_right = 86.0
|
||||
margin_bottom = 29.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
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
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/LinkButton"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -11.0
|
||||
margin_top = -11.0
|
||||
margin_right = 11.0
|
||||
margin_bottom = 11.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
texture = ExtResource( 4 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LayerName" type="HBoxContainer" parent="HBoxContainer"]
|
||||
margin_left = 94.0
|
||||
margin_right = 198.0
|
||||
margin_left = 126.0
|
||||
margin_right = 236.0
|
||||
margin_bottom = 36.0
|
||||
rect_min_size = Vector2( 104, 0 )
|
||||
rect_min_size = Vector2( 110, 0 )
|
||||
rect_pivot_offset = Vector2( -187, -9 )
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_horizontal = 10
|
||||
alignment = 1
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="HierarchySpacer" type="Control" parent="HBoxContainer/LayerName"]
|
||||
margin_bottom = 36.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="Label" type="Label" parent="HBoxContainer/LayerName"]
|
||||
margin_left = 4.0
|
||||
margin_top = 11.0
|
||||
margin_right = 104.0
|
||||
margin_right = 106.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 )
|
||||
margin_left = 30.0
|
||||
margin_top = 2.0
|
||||
margin_right = 110.0
|
||||
margin_bottom = 34.0
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 4
|
||||
text = "Layer 0"
|
||||
editable = false
|
||||
caret_blink = true
|
||||
caret_blink_speed = 0.5
|
||||
|
||||
[node name="EmptySpacer" type="Control" parent="HBoxContainer/LayerName"]
|
||||
margin_left = 110.0
|
||||
margin_right = 110.0
|
||||
margin_bottom = 36.0
|
||||
mouse_filter = 2
|
||||
|
||||
[connection signal="gui_input" from="." to="." method="_on_LayerContainer_gui_input"]
|
||||
[connection signal="pressed" from="HBoxContainer/LayerButtons/ExpandButton" to="." method="_on_ExpandButton_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"]
|
|
@ -4,10 +4,10 @@ enum MenuOptions { DELETE, LINK, PROPERTIES }
|
|||
|
||||
var frame := 0
|
||||
var layer := 0
|
||||
var cel: Cel
|
||||
var image: Image
|
||||
var cel: BaseCel
|
||||
|
||||
onready var popup_menu: PopupMenu = $PopupMenu
|
||||
onready var popup_menu: PopupMenu = get_node_or_null("PopupMenu")
|
||||
onready var linked_indicator: Polygon2D = get_node_or_null("LinkedIndicator")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
|
@ -19,30 +19,31 @@ func button_setup() -> void:
|
|||
rect_min_size.y = Global.animation_timeline.cel_size
|
||||
|
||||
hint_tooltip = tr("Frame: %s, Layer: %s") % [frame + 1, layer]
|
||||
if Global.current_project.frames[frame] in Global.current_project.layers[layer].linked_cels:
|
||||
get_node("LinkedIndicator").visible = true
|
||||
popup_menu.set_item_text(MenuOptions.LINK, "Unlink Cel")
|
||||
popup_menu.set_item_metadata(MenuOptions.LINK, "Unlink Cel")
|
||||
else:
|
||||
get_node("LinkedIndicator").visible = false
|
||||
popup_menu.set_item_text(MenuOptions.LINK, "Link Cel")
|
||||
popup_menu.set_item_metadata(MenuOptions.LINK, "Link Cel")
|
||||
if is_instance_valid(linked_indicator):
|
||||
if Global.current_project.frames[frame] in Global.current_project.layers[layer].linked_cels:
|
||||
linked_indicator.visible = true
|
||||
popup_menu.set_item_text(MenuOptions.LINK, "Unlink Cel")
|
||||
popup_menu.set_item_metadata(MenuOptions.LINK, "Unlink Cel")
|
||||
else:
|
||||
linked_indicator.visible = false
|
||||
popup_menu.set_item_text(MenuOptions.LINK, "Link Cel")
|
||||
popup_menu.set_item_metadata(MenuOptions.LINK, "Link Cel")
|
||||
|
||||
# Reset the checkers size because it assumes you want the same size as the canvas
|
||||
var checker = $CelTexture/TransparentChecker
|
||||
checker.rect_size = checker.get_parent().rect_size
|
||||
cel = Global.current_project.frames[frame].cels[layer]
|
||||
image = cel.image
|
||||
|
||||
|
||||
func _on_CelButton_resized() -> void:
|
||||
get_node("CelTexture").rect_min_size.x = rect_min_size.x - 4
|
||||
get_node("CelTexture").rect_min_size.y = rect_min_size.y - 4
|
||||
|
||||
get_node("LinkedIndicator").polygon[1].x = rect_min_size.x
|
||||
get_node("LinkedIndicator").polygon[2].x = rect_min_size.x
|
||||
get_node("LinkedIndicator").polygon[2].y = rect_min_size.y
|
||||
get_node("LinkedIndicator").polygon[3].y = rect_min_size.y
|
||||
if is_instance_valid(linked_indicator):
|
||||
linked_indicator.polygon[1].x = rect_min_size.x
|
||||
linked_indicator.polygon[2].x = rect_min_size.x
|
||||
linked_indicator.polygon[2].y = rect_min_size.y
|
||||
linked_indicator.polygon[3].y = rect_min_size.y
|
||||
|
||||
|
||||
func _on_CelButton_pressed() -> void:
|
||||
|
@ -88,7 +89,8 @@ func _on_CelButton_pressed() -> void:
|
|||
release_focus()
|
||||
|
||||
elif Input.is_action_just_released("right_mouse"):
|
||||
popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE))
|
||||
if is_instance_valid(popup_menu):
|
||||
popup_menu.popup(Rect2(get_global_mouse_position(), Vector2.ONE))
|
||||
pressed = !pressed
|
||||
elif Input.is_action_just_released("middle_mouse"):
|
||||
pressed = !pressed
|
||||
|
@ -103,76 +105,71 @@ func _on_PopupMenu_id_pressed(id: int) -> void:
|
|||
_delete_cel_content()
|
||||
|
||||
MenuOptions.LINK:
|
||||
var f: Frame = Global.current_project.frames[frame]
|
||||
var cel_index: int = Global.current_project.layers[layer].linked_cels.find(f)
|
||||
var new_layers: Array = Global.current_project.duplicate_layers()
|
||||
var new_cels: Array = f.cels.duplicate()
|
||||
for i in new_cels.size():
|
||||
new_cels[i] = Cel.new(
|
||||
new_cels[i].image, new_cels[i].opacity, new_cels[i].image_texture
|
||||
)
|
||||
|
||||
var project: Project = Global.current_project
|
||||
var f: Frame = project.frames[frame]
|
||||
var cel_index: int = project.layers[layer].linked_cels.find(f)
|
||||
var new_linked_cels: Array = project.layers[layer].linked_cels.duplicate()
|
||||
if popup_menu.get_item_metadata(MenuOptions.LINK) == "Unlink Cel":
|
||||
new_layers[layer].linked_cels.remove(cel_index)
|
||||
var sprite := Image.new()
|
||||
sprite.copy_from(f.cels[layer].image)
|
||||
var sprite_texture := ImageTexture.new()
|
||||
sprite_texture.create_from_image(sprite, 0)
|
||||
new_cels[layer].image = sprite
|
||||
new_cels[layer].image_texture = sprite_texture
|
||||
|
||||
Global.current_project.undo_redo.create_action("Unlink Cel")
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "layers", new_layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
new_linked_cels.remove(cel_index)
|
||||
project.undo_redo.create_action("Unlink Cel")
|
||||
project.undo_redo.add_do_property(cel, "image_texture", ImageTexture.new())
|
||||
project.undo_redo.add_undo_property(cel, "image_texture", cel.image_texture)
|
||||
project.undo_redo.add_do_method(cel, "set_content", cel.copy_content())
|
||||
project.undo_redo.add_undo_method(cel, "set_content", cel.get_content())
|
||||
|
||||
elif popup_menu.get_item_metadata(MenuOptions.LINK) == "Link Cel":
|
||||
new_layers[layer].linked_cels.append(f)
|
||||
Global.current_project.undo_redo.create_action("Link Cel")
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "layers", new_layers
|
||||
)
|
||||
if new_layers[layer].linked_cels.size() > 1:
|
||||
new_linked_cels.append(f)
|
||||
project.undo_redo.create_action("Link Cel")
|
||||
if new_linked_cels.size() > 1:
|
||||
# If there are already linked cels, set the current cel's image
|
||||
# to the first linked cel's image
|
||||
new_cels[layer].image = new_layers[layer].linked_cels[0].cels[layer].image
|
||||
new_cels[layer].image_texture = new_layers[layer].linked_cels[0].cels[layer].image_texture
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
var linked_cel: BaseCel = project.layers[layer].linked_cels[0].cels[layer]
|
||||
project.undo_redo.add_do_property(
|
||||
cel, "image_texture", linked_cel.image_texture
|
||||
)
|
||||
project.undo_redo.add_undo_property(cel, "image_texture", cel.image_texture)
|
||||
project.undo_redo.add_do_method(cel, "set_content", linked_cel.get_content())
|
||||
project.undo_redo.add_undo_method(cel, "set_content", cel.get_content())
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undo_redo.add_do_property(project.layers[layer], "linked_cels", new_linked_cels)
|
||||
project.undo_redo.add_undo_property(
|
||||
project.layers[layer], "linked_cels", project.layers[layer].linked_cels
|
||||
)
|
||||
# Remove and add a new cel button to update appearance (can't use self.button_setup
|
||||
# because there is no guarantee that it will be the exact same cel button instance)
|
||||
project.undo_redo.add_do_method(
|
||||
Global.animation_timeline, "project_cel_removed", frame, layer
|
||||
)
|
||||
project.undo_redo.add_undo_method(
|
||||
Global.animation_timeline, "project_cel_removed", frame, layer
|
||||
)
|
||||
project.undo_redo.add_do_method(
|
||||
Global.animation_timeline, "project_cel_added", frame, layer
|
||||
)
|
||||
project.undo_redo.add_undo_method(
|
||||
Global.animation_timeline, "project_cel_added", frame, layer
|
||||
)
|
||||
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _delete_cel_content() -> void:
|
||||
if image.is_invisible():
|
||||
return
|
||||
var curr_layer: Layer = Global.current_project.layers[layer]
|
||||
if !curr_layer.can_layer_get_drawn():
|
||||
return
|
||||
var project = Global.current_project
|
||||
image.unlock()
|
||||
var data := image.data
|
||||
var empty_content = cel.create_empty_content()
|
||||
var old_content = cel.get_content()
|
||||
project.undos += 1
|
||||
project.undo_redo.create_action("Draw")
|
||||
project.undo_redo.add_undo_property(image, "data", data)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true, frame, layer, project)
|
||||
image.fill(0)
|
||||
project.undo_redo.add_do_property(image, "data", image.data)
|
||||
if project.frames[frame] in project.layers[layer].linked_cels:
|
||||
for f in project.layers[layer].linked_cels:
|
||||
project.undo_redo.add_do_method(f.cels[layer], "set_content", empty_content)
|
||||
project.undo_redo.add_undo_method(f.cels[layer], "set_content", old_content)
|
||||
else:
|
||||
project.undo_redo.add_do_method(cel, "set_content", empty_content)
|
||||
project.undo_redo.add_undo_method(cel, "set_content", old_content)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false, frame, layer, project)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true, frame, layer, project)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
|
@ -192,72 +189,70 @@ func get_drag_data(_position) -> Array:
|
|||
|
||||
|
||||
func can_drop_data(_pos, data) -> bool:
|
||||
var project: Project = Global.current_project
|
||||
if typeof(data) == TYPE_ARRAY and data[0] == "Cel":
|
||||
var new_frame = data[1]
|
||||
var new_layer = data[2]
|
||||
if (
|
||||
Global.current_project.frames[frame] in Global.current_project.layers[layer].linked_cels
|
||||
or (
|
||||
Global.current_project.frames[new_frame]
|
||||
in Global.current_project.layers[new_layer].linked_cels
|
||||
)
|
||||
):
|
||||
# If the cel we're dragging or the cel we are targeting are linked, don't allow dragging
|
||||
return false
|
||||
else:
|
||||
return true
|
||||
else:
|
||||
return false
|
||||
var drag_frame = data[1]
|
||||
var drag_layer = data[2]
|
||||
if project.layers[drag_layer].get_script() == project.layers[layer].get_script():
|
||||
if (
|
||||
project.layers[layer] is GroupLayer
|
||||
or not (
|
||||
(project.frames[frame] in project.layers[layer].linked_cels)
|
||||
or (project.frames[drag_frame] in project.layers[drag_layer].linked_cels)
|
||||
)
|
||||
):
|
||||
if not (drag_frame == frame and drag_layer == layer):
|
||||
var region: Rect2
|
||||
if Input.is_action_pressed("ctrl") or layer != drag_layer: # Swap cels
|
||||
region = get_global_rect()
|
||||
else: # Move cels
|
||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left
|
||||
region = _get_region_rect(-0.125, 0.125)
|
||||
region.position.x -= 2 # Container spacing
|
||||
else: # Right
|
||||
region = _get_region_rect(0.875, 1.125)
|
||||
region.position.x += 2 # Container spacing
|
||||
Global.animation_timeline.drag_highlight.rect_global_position = region.position
|
||||
Global.animation_timeline.drag_highlight.rect_size = region.size
|
||||
Global.animation_timeline.drag_highlight.visible = true
|
||||
return true
|
||||
|
||||
Global.animation_timeline.drag_highlight.visible = false
|
||||
return false
|
||||
|
||||
|
||||
func drop_data(_pos, data) -> void:
|
||||
var new_frame = data[1]
|
||||
var new_layer = data[2]
|
||||
if new_frame == frame and new_layer == layer:
|
||||
return
|
||||
var drop_frame = data[1]
|
||||
var drop_layer = data[2]
|
||||
var project = Global.current_project
|
||||
|
||||
var this_frame_new_cels = Global.current_project.frames[frame].cels.duplicate()
|
||||
var new_frame_new_cels
|
||||
var temp = this_frame_new_cels[layer]
|
||||
this_frame_new_cels[layer] = Global.current_project.frames[new_frame].cels[new_layer]
|
||||
if frame == new_frame:
|
||||
this_frame_new_cels[new_layer] = temp
|
||||
else:
|
||||
new_frame_new_cels = Global.current_project.frames[new_frame].cels.duplicate()
|
||||
new_frame_new_cels[new_layer] = temp
|
||||
project.undo_redo.create_action("Move Cels")
|
||||
if Input.is_action_pressed("ctrl") or layer != drop_layer: # Swap cels
|
||||
project.undo_redo.add_do_method(project, "swap_cel", frame, layer, drop_frame, drop_layer)
|
||||
project.undo_redo.add_undo_method(project, "swap_cel", frame, layer, drop_frame, drop_layer)
|
||||
else: # Move cels
|
||||
var to_frame: int
|
||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left
|
||||
to_frame = frame
|
||||
else: # Right
|
||||
to_frame = frame + 1
|
||||
if drop_frame < frame:
|
||||
to_frame -= 1
|
||||
project.undo_redo.add_do_method(project, "move_cel", drop_frame, to_frame, layer)
|
||||
project.undo_redo.add_undo_method(project, "move_cel", to_frame, drop_frame, layer)
|
||||
|
||||
Global.current_project.undo_redo.create_action("Move Cels")
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project.frames[frame], "cels", this_frame_new_cels
|
||||
)
|
||||
project.undo_redo.add_do_property(project, "current_layer", layer)
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
if frame != drop_frame: # If the cel moved to a different frame
|
||||
project.undo_redo.add_do_property(project, "current_frame", frame)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "current_layer", layer)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
)
|
||||
|
||||
if frame != new_frame: # If the cel moved to a different frame
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project.frames[new_frame], "cels", new_frame_new_cels
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", frame
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_frame", Global.current_project.current_frame
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project.frames[new_frame],
|
||||
"cels",
|
||||
Global.current_project.frames[new_frame].cels
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project.frames[frame], "cels", Global.current_project.frames[frame].cels
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
func _get_region_rect(x_begin: float, x_end: float) -> Rect2:
|
||||
var rect := get_global_rect()
|
||||
rect.position.x += rect.size.x * x_begin
|
||||
rect.size.x *= x_end - x_begin
|
||||
return rect
|
||||
|
|
|
@ -7,6 +7,8 @@ onready var frame_properties: ConfirmationDialog = Global.control.find_node("Fra
|
|||
|
||||
|
||||
func _ready() -> void:
|
||||
rect_min_size.x = Global.animation_timeline.cel_size
|
||||
text = str(frame + 1)
|
||||
connect("pressed", self, "_button_pressed")
|
||||
connect("mouse_entered", self, "_update_tooltip")
|
||||
|
||||
|
@ -85,33 +87,21 @@ func _on_PopupMenu_id_pressed(id: int) -> void:
|
|||
|
||||
func change_frame_order(rate: int) -> void:
|
||||
var change = frame + rate
|
||||
var new_frames: Array = Global.current_project.frames.duplicate()
|
||||
var temp = new_frames[frame]
|
||||
new_frames[frame] = new_frames[change]
|
||||
new_frames[change] = temp
|
||||
var project = Global.current_project
|
||||
|
||||
Global.current_project.undo_redo.create_action("Change Frame Order")
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "frames", new_frames)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "frames", Global.current_project.frames
|
||||
)
|
||||
project.undo_redo.create_action("Change Frame Order")
|
||||
project.undo_redo.add_do_method(project, "move_frame", frame, change)
|
||||
project.undo_redo.add_undo_method(project, "move_frame", change, frame)
|
||||
|
||||
if Global.current_project.current_frame == frame:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", change
|
||||
)
|
||||
if project.current_frame == frame:
|
||||
project.undo_redo.add_do_property(project, "current_frame", change)
|
||||
else:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", Global.current_project.current_frame
|
||||
)
|
||||
project.undo_redo.add_do_property(project, "current_frame", project.current_frame)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_frame", Global.current_project.current_frame
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func get_drag_data(_position) -> Array:
|
||||
|
@ -126,40 +116,56 @@ func get_drag_data(_position) -> Array:
|
|||
|
||||
func can_drop_data(_pos, data) -> bool:
|
||||
if typeof(data) == TYPE_ARRAY:
|
||||
return data[0] == "Frame"
|
||||
else:
|
||||
return false
|
||||
if data[0] == "Frame":
|
||||
if data[1] != frame: # Can't move to same frame
|
||||
var region: Rect2
|
||||
if Input.is_action_pressed("ctrl"): # Swap frames
|
||||
region = get_global_rect()
|
||||
else: # Move frames
|
||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
|
||||
region = _get_region_rect(-0.125, 0.125)
|
||||
region.position.x -= 2 # Container spacing
|
||||
else:
|
||||
region = _get_region_rect(0.875, 1.125)
|
||||
region.position.x += 2 # Container spacing
|
||||
Global.animation_timeline.drag_highlight.rect_global_position = region.position
|
||||
Global.animation_timeline.drag_highlight.rect_size = region.size
|
||||
Global.animation_timeline.drag_highlight.visible = true
|
||||
return true
|
||||
Global.animation_timeline.drag_highlight.visible = false
|
||||
return false
|
||||
|
||||
|
||||
func drop_data(_pos, data) -> void:
|
||||
var new_frame = data[1]
|
||||
if frame == new_frame:
|
||||
return
|
||||
var drop_frame = data[1]
|
||||
var project = Global.current_project
|
||||
project.undo_redo.create_action("Change Frame Order")
|
||||
if Input.is_action_pressed("ctrl"): # Swap frames
|
||||
project.undo_redo.add_do_method(project, "swap_frame", frame, drop_frame)
|
||||
project.undo_redo.add_undo_method(project, "swap_frame", frame, drop_frame)
|
||||
else: # Move frames
|
||||
var to_frame: int
|
||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()): # Left
|
||||
to_frame = frame
|
||||
else: # Right
|
||||
to_frame = frame + 1
|
||||
if drop_frame < frame:
|
||||
to_frame -= 1
|
||||
project.undo_redo.add_do_method(project, "move_frame", drop_frame, to_frame)
|
||||
project.undo_redo.add_undo_method(project, "move_frame", to_frame, drop_frame)
|
||||
|
||||
var new_frames: Array = Global.current_project.frames.duplicate()
|
||||
var temp = new_frames[frame]
|
||||
new_frames[frame] = new_frames[new_frame]
|
||||
new_frames[new_frame] = temp
|
||||
|
||||
Global.current_project.undo_redo.create_action("Change Frame Order")
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "frames", new_frames)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "frames", Global.current_project.frames
|
||||
)
|
||||
|
||||
if Global.current_project.current_frame == new_frame:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", frame
|
||||
)
|
||||
if project.current_frame == drop_frame:
|
||||
project.undo_redo.add_do_property(project, "current_frame", frame)
|
||||
else:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_frame", Global.current_project.current_frame
|
||||
)
|
||||
project.undo_redo.add_do_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_property(project, "current_frame", project.current_frame)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_frame", Global.current_project.current_frame
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
func _get_region_rect(x_begin: float, x_end: float) -> Rect2:
|
||||
var rect := get_global_rect()
|
||||
rect.position.x += rect.size.x * x_begin
|
||||
rect.size.x *= x_end - x_begin
|
||||
return rect
|
||||
|
|
|
@ -5,9 +5,11 @@
|
|||
[node name="FrameButton" type="Button"]
|
||||
margin_right = 12.0
|
||||
margin_bottom = 20.0
|
||||
focus_mode = 0
|
||||
mouse_default_cursor_shape = 2
|
||||
toggle_mode = true
|
||||
button_mask = 7
|
||||
enabled_focus_mode = 0
|
||||
text = "1"
|
||||
script = ExtResource( 1 )
|
||||
__meta__ = {
|
||||
|
|
10
src/UI/Timeline/GroupCelButton.tscn
Normal file
10
src/UI/Timeline/GroupCelButton.tscn
Normal file
|
@ -0,0 +1,10 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Timeline/BaseCelButton.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://src/UI/Timeline/CelButton.gd" type="Script" id=2]
|
||||
|
||||
[node name="GroupCelButton" instance=ExtResource( 1 )]
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="TransparentChecker" parent="CelTexture" index="0"]
|
||||
visible = false
|
10
src/UI/Timeline/GroupLayerButton.tscn
Normal file
10
src/UI/Timeline/GroupLayerButton.tscn
Normal file
|
@ -0,0 +1,10 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Timeline/BaseLayerButton.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://assets/graphics/layers/group_expanded.png" type="Texture" id=4]
|
||||
|
||||
[node name="GroupLayerButton" instance=ExtResource( 1 )]
|
||||
hide_expand_button = false
|
||||
|
||||
[node name="TextureRect" parent="HBoxContainer/LayerButtons/ExpandButton" index="0"]
|
||||
texture = ExtResource( 4 )
|
|
@ -1,28 +1,54 @@
|
|||
class_name LayerButton
|
||||
extends Button
|
||||
|
||||
const HIERARCHY_DEPTH_PIXEL_SHIFT = 8
|
||||
|
||||
export var hide_expand_button := true
|
||||
|
||||
var layer := 0
|
||||
|
||||
onready var expand_button: BaseButton = find_node("ExpandButton")
|
||||
onready var visibility_button: BaseButton = find_node("VisibilityButton")
|
||||
onready var lock_button: BaseButton = find_node("LockButton")
|
||||
onready var linked_button: BaseButton = find_node("LinkButton")
|
||||
onready var label: Label = find_node("Label")
|
||||
onready var line_edit: LineEdit = find_node("LineEdit")
|
||||
onready var hierarchy_spacer: Control = find_node("HierarchySpacer")
|
||||
onready var linked_button: BaseButton = find_node("LinkButton")
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
rect_min_size.y = Global.animation_timeline.cel_size
|
||||
|
||||
label.text = Global.current_project.layers[layer].name
|
||||
line_edit.text = Global.current_project.layers[layer].name
|
||||
|
||||
var layer_buttons = find_node("LayerButtons")
|
||||
for child in layer_buttons.get_children():
|
||||
var texture = child.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/%s" % [button_category, normal_file_name])
|
||||
texture.modulate = Global.modulate_icon_color
|
||||
|
||||
# Visualize how deep into the hierarchy the layer is
|
||||
var hierarchy_depth: int = Global.current_project.layers[layer].get_hierarchy_depth()
|
||||
hierarchy_spacer.rect_min_size.x = hierarchy_depth * HIERARCHY_DEPTH_PIXEL_SHIFT
|
||||
|
||||
if Global.control.theme.get_color("font_color", "Button").v > 0.5: # Light text is dark theme
|
||||
self_modulate.v = 1 + hierarchy_depth * 0.4
|
||||
else: # Dark text should be light theme
|
||||
self_modulate.v = 1 - hierarchy_depth * 0.075
|
||||
|
||||
update_buttons()
|
||||
|
||||
|
||||
func update_buttons() -> void:
|
||||
if hide_expand_button:
|
||||
expand_button.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
expand_button.get_child(0).visible = false # Hide the TextureRect
|
||||
else:
|
||||
if Global.current_project.layers[layer].expanded:
|
||||
Global.change_button_texturerect(expand_button.get_child(0), "group_expanded.png")
|
||||
else:
|
||||
Global.change_button_texturerect(expand_button.get_child(0), "group_collapsed.png")
|
||||
|
||||
if Global.current_project.layers[layer].visible:
|
||||
Global.change_button_texturerect(visibility_button.get_child(0), "layer_visible.png")
|
||||
else:
|
||||
|
@ -33,10 +59,40 @@ func _ready() -> void:
|
|||
else:
|
||||
Global.change_button_texturerect(lock_button.get_child(0), "unlock.png")
|
||||
|
||||
if Global.current_project.layers[layer].new_cels_linked: # If new layers will be linked
|
||||
Global.change_button_texturerect(linked_button.get_child(0), "linked_layer.png")
|
||||
else:
|
||||
Global.change_button_texturerect(linked_button.get_child(0), "unlinked_layer.png")
|
||||
if linked_button:
|
||||
if Global.current_project.layers[layer].new_cels_linked: # If new layers will be linked
|
||||
Global.change_button_texturerect(linked_button.get_child(0), "linked_layer.png")
|
||||
else:
|
||||
Global.change_button_texturerect(linked_button.get_child(0), "unlinked_layer.png")
|
||||
|
||||
visibility_button.modulate.a = 1
|
||||
lock_button.modulate.a = 1
|
||||
if is_instance_valid(Global.current_project.layers[layer].parent):
|
||||
if not Global.current_project.layers[layer].parent.is_visible_in_hierarchy():
|
||||
visibility_button.modulate.a = 0.33
|
||||
if Global.current_project.layers[layer].parent.is_locked_in_hierarchy():
|
||||
lock_button.modulate.a = 0.33
|
||||
|
||||
|
||||
# Used when pressing a button on this changes the appearnce of other layers (ie: expand or visible)
|
||||
func _update_buttons_all_layers() -> void:
|
||||
for layer_button in Global.layers_container.get_children():
|
||||
layer_button.update_buttons()
|
||||
var expanded = Global.current_project.layers[layer_button.layer].is_expanded_in_hierarchy()
|
||||
layer_button.visible = expanded
|
||||
Global.frames_container.get_child(layer_button.get_index()).visible = expanded
|
||||
|
||||
|
||||
func _draw() -> void:
|
||||
if hierarchy_spacer.rect_size.x > 0.1:
|
||||
var color := Color(1, 1, 1, 0.33)
|
||||
color.v = round(Global.control.theme.get_color("font_color", "Button").v)
|
||||
var x = (
|
||||
hierarchy_spacer.rect_global_position.x
|
||||
- rect_global_position.x
|
||||
+ hierarchy_spacer.rect_size.x
|
||||
)
|
||||
draw_line(Vector2(x, 0), Vector2(x, rect_size.y), color)
|
||||
|
||||
|
||||
func _input(event: InputEvent) -> void:
|
||||
|
@ -89,37 +145,44 @@ func _save_layer_name(new_name: String) -> void:
|
|||
line_edit.visible = false
|
||||
line_edit.editable = false
|
||||
label.text = new_name
|
||||
Global.layers_changed_skip = true
|
||||
Global.current_project.layers[layer].name = new_name
|
||||
|
||||
|
||||
func _on_ExpandButton_pressed():
|
||||
Global.current_project.layers[layer].expanded = !Global.current_project.layers[layer].expanded
|
||||
_update_buttons_all_layers()
|
||||
|
||||
|
||||
func _on_VisibilityButton_pressed() -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
Global.current_project.layers[layer].visible = !Global.current_project.layers[layer].visible
|
||||
Global.canvas.update()
|
||||
_select_current_layer()
|
||||
_update_buttons_all_layers()
|
||||
|
||||
|
||||
func _on_LockButton_pressed() -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
Global.current_project.layers[layer].locked = !Global.current_project.layers[layer].locked
|
||||
_select_current_layer()
|
||||
_update_buttons_all_layers()
|
||||
|
||||
|
||||
func _on_LinkButton_pressed() -> void:
|
||||
Global.canvas.selection.transform_content_confirm()
|
||||
var layer_class: Layer = Global.current_project.layers[layer]
|
||||
var layer_class: PixelLayer = Global.current_project.layers[layer]
|
||||
layer_class.new_cels_linked = !layer_class.new_cels_linked
|
||||
if layer_class.new_cels_linked && !layer_class.linked_cels:
|
||||
# If button is pressed and there are no linked cels in the layer
|
||||
layer_class.linked_cels.append(
|
||||
Global.current_project.frames[Global.current_project.current_frame]
|
||||
)
|
||||
var container = Global.frames_container.get_child(Global.current_project.current_layer)
|
||||
var container = Global.frames_container.get_child(
|
||||
Global.frames_container.get_child_count() - 1 - layer
|
||||
)
|
||||
container.get_child(Global.current_project.current_frame).button_setup()
|
||||
|
||||
_select_current_layer()
|
||||
Global.current_project.layers = Global.current_project.layers # Call the setter
|
||||
update_buttons()
|
||||
|
||||
|
||||
func _select_current_layer() -> void:
|
||||
|
@ -132,53 +195,171 @@ func _select_current_layer() -> void:
|
|||
|
||||
|
||||
func get_drag_data(_position) -> Array:
|
||||
var button := Button.new()
|
||||
button.rect_size = rect_size
|
||||
button.theme = Global.control.theme
|
||||
button.text = label.text
|
||||
set_drag_preview(button)
|
||||
var layers := range(
|
||||
layer - Global.current_project.layers[layer].get_child_count(true), layer + 1
|
||||
)
|
||||
|
||||
var box := VBoxContainer.new()
|
||||
for i in layers.size():
|
||||
var button := Button.new()
|
||||
button.rect_min_size = rect_size
|
||||
button.theme = Global.control.theme
|
||||
button.text = Global.current_project.layers[layers[-1 - i]].name
|
||||
box.add_child(button)
|
||||
set_drag_preview(box)
|
||||
|
||||
return ["Layer", layer]
|
||||
|
||||
|
||||
func can_drop_data(_pos, data) -> bool:
|
||||
if typeof(data) == TYPE_ARRAY:
|
||||
return data[0] == "Layer"
|
||||
else:
|
||||
return false
|
||||
if data[0] == "Layer":
|
||||
var curr_layer: BaseLayer = Global.current_project.layers[layer]
|
||||
var drag_layer: BaseLayer = Global.current_project.layers[data[1]]
|
||||
|
||||
if curr_layer == drag_layer:
|
||||
Global.animation_timeline.drag_highlight.visible = false
|
||||
return false
|
||||
|
||||
var region: Rect2
|
||||
var depth: int = Global.current_project.layers[layer].get_hierarchy_depth()
|
||||
|
||||
if Input.is_action_pressed("ctrl"): # Swap layers
|
||||
if drag_layer.is_a_parent_of(curr_layer) or curr_layer.is_a_parent_of(drag_layer):
|
||||
Global.animation_timeline.drag_highlight.visible = false
|
||||
return false
|
||||
region = get_global_rect()
|
||||
|
||||
else: # Shift layers
|
||||
if drag_layer.is_a_parent_of(curr_layer):
|
||||
Global.animation_timeline.drag_highlight.visible = false
|
||||
return false
|
||||
# If accepted as a child, is it in the center region?
|
||||
if (
|
||||
Global.current_project.layers[layer].accepts_child(data[1])
|
||||
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
|
||||
):
|
||||
# Drawn regions are adusted a bit from actual to clearify drop position
|
||||
region = _get_region_rect(0.15, 0.85)
|
||||
depth += 1
|
||||
else:
|
||||
# Top or bottom region?
|
||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
|
||||
region = _get_region_rect(-0.1, 0.15)
|
||||
else:
|
||||
region = _get_region_rect(0.85, 1.1)
|
||||
# Shift drawn region to the right a bit for hierarchy depth visualization:
|
||||
region.position.x += depth * HIERARCHY_DEPTH_PIXEL_SHIFT
|
||||
region.size.x -= depth * HIERARCHY_DEPTH_PIXEL_SHIFT
|
||||
Global.animation_timeline.drag_highlight.rect_global_position = region.position
|
||||
Global.animation_timeline.drag_highlight.rect_size = region.size
|
||||
Global.animation_timeline.drag_highlight.visible = true
|
||||
return true
|
||||
Global.animation_timeline.drag_highlight.visible = false
|
||||
return false
|
||||
|
||||
|
||||
func drop_data(_pos, data) -> void:
|
||||
var new_layer = data[1]
|
||||
if layer == new_layer:
|
||||
return
|
||||
var drop_layer: int = data[1]
|
||||
var project = Global.current_project
|
||||
|
||||
var new_layers: Array = Global.current_project.layers.duplicate()
|
||||
var temp = new_layers[layer]
|
||||
new_layers[layer] = new_layers[new_layer]
|
||||
new_layers[new_layer] = temp
|
||||
project.undo_redo.create_action("Change Layer Order")
|
||||
var layers: Array = project.layers # This shouldn't be modified directly
|
||||
|
||||
Global.current_project.undo_redo.create_action("Change Layer Order")
|
||||
for f in Global.current_project.frames:
|
||||
var new_cels: Array = f.cels.duplicate()
|
||||
var temp_canvas = new_cels[layer]
|
||||
new_cels[layer] = new_cels[new_layer]
|
||||
new_cels[new_layer] = temp_canvas
|
||||
Global.current_project.undo_redo.add_do_property(f, "cels", new_cels)
|
||||
Global.current_project.undo_redo.add_undo_property(f, "cels", f.cels)
|
||||
|
||||
if Global.current_project.current_layer == layer:
|
||||
Global.current_project.undo_redo.add_do_property(
|
||||
Global.current_project, "current_layer", new_layer
|
||||
)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "current_layer", Global.current_project.current_layer
|
||||
)
|
||||
Global.current_project.undo_redo.add_do_property(Global.current_project, "layers", new_layers)
|
||||
Global.current_project.undo_redo.add_undo_property(
|
||||
Global.current_project, "layers", Global.current_project.layers
|
||||
var drop_from_indices := range(
|
||||
drop_layer - layers[drop_layer].get_child_count(true), drop_layer + 1
|
||||
)
|
||||
|
||||
Global.current_project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
Global.current_project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
Global.current_project.undo_redo.commit_action()
|
||||
var drop_from_parents := []
|
||||
for i in range(drop_from_indices.size()):
|
||||
drop_from_parents.append(layers[drop_from_indices[i]].parent)
|
||||
|
||||
if Input.is_action_pressed("ctrl"): # Swap layers
|
||||
# a and b both need "from", "to", and "to_parents"
|
||||
# a is this layer (and children), b is the dropped layers
|
||||
var a := {"from": range(layer - layers[layer].get_child_count(true), layer + 1)}
|
||||
var b := {"from": drop_from_indices}
|
||||
|
||||
if a.from[0] < b.from[0]:
|
||||
a["to"] = range(b.from[-1] + 1 - a.from.size(), b.from[-1] + 1) # Size of a, start from end of b
|
||||
b["to"] = range(a.from[0], a.from[0] + b.from.size()) # Size of b, start from beginning of a
|
||||
else:
|
||||
a["to"] = range(b.from[0], b.from[0] + a.from.size()) # Size of a, start from beginning of b
|
||||
b["to"] = range(a.from[-1] + 1 - b.from.size(), a.from[-1] + 1) # Size of b, start from end of a
|
||||
|
||||
var a_from_parents := []
|
||||
for l in a.from:
|
||||
a_from_parents.append(layers[l].parent)
|
||||
|
||||
# to_parents starts as a dulpicate of from_parents, set the root layer's (with one layer or
|
||||
# group with its children, this will always be the last layer [-1]) parent to the other
|
||||
# root layer's parent
|
||||
a["to_parents"] = a_from_parents.duplicate()
|
||||
b["to_parents"] = drop_from_parents.duplicate()
|
||||
a.to_parents[-1] = drop_from_parents[-1]
|
||||
b.to_parents[-1] = a_from_parents[-1]
|
||||
|
||||
project.undo_redo.add_do_method(project, "swap_layers", a, b)
|
||||
project.undo_redo.add_undo_method(
|
||||
project,
|
||||
"swap_layers",
|
||||
{"from": a.to, "to": a.from, "to_parents": a_from_parents},
|
||||
{"from": b.to, "to": drop_from_indices, "to_parents": drop_from_parents}
|
||||
)
|
||||
|
||||
else: # Move layers
|
||||
var to_index: int # the index where the LOWEST moved layer should end up
|
||||
var to_parent: BaseLayer
|
||||
|
||||
# If accepted as a child, is it in the center region?
|
||||
if (
|
||||
layers[layer].accepts_child(data[1])
|
||||
and _get_region_rect(0.25, 0.75).has_point(get_global_mouse_position())
|
||||
):
|
||||
to_index = layer
|
||||
to_parent = layers[layer]
|
||||
else:
|
||||
# Top or bottom region?
|
||||
if _get_region_rect(0, 0.5).has_point(get_global_mouse_position()):
|
||||
to_index = layer + 1
|
||||
to_parent = layers[layer].parent
|
||||
else:
|
||||
# Place under the layer, if it has children, place after its lowest child
|
||||
if layers[layer].has_children():
|
||||
to_index = layers[layer].get_children(true)[0].index
|
||||
|
||||
if layers[layer].is_a_parent_of(layers[drop_layer]):
|
||||
to_index += drop_from_indices.size()
|
||||
else:
|
||||
to_index = layer
|
||||
to_parent = layers[layer].parent
|
||||
|
||||
if drop_layer < layer:
|
||||
to_index -= drop_from_indices.size()
|
||||
|
||||
var drop_to_indices := range(to_index, to_index + drop_from_indices.size())
|
||||
|
||||
var to_parents := drop_from_parents.duplicate()
|
||||
to_parents[-1] = to_parent
|
||||
|
||||
project.undo_redo.add_do_method(
|
||||
project, "move_layers", drop_from_indices, drop_to_indices, to_parents
|
||||
)
|
||||
project.undo_redo.add_undo_method(
|
||||
project, "move_layers", drop_to_indices, drop_from_indices, drop_from_parents
|
||||
)
|
||||
if project.current_layer == drop_layer:
|
||||
project.undo_redo.add_do_property(project, "current_layer", layer)
|
||||
else:
|
||||
project.undo_redo.add_do_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_undo_property(project, "current_layer", project.current_layer)
|
||||
project.undo_redo.add_undo_method(Global, "undo_or_redo", true)
|
||||
project.undo_redo.add_do_method(Global, "undo_or_redo", false)
|
||||
project.undo_redo.commit_action()
|
||||
|
||||
|
||||
func _get_region_rect(y_begin: float, y_end: float) -> Rect2:
|
||||
var rect := get_global_rect()
|
||||
rect.position.y += rect.size.y * y_begin
|
||||
rect.size.y *= y_end - y_begin
|
||||
return rect
|
||||
|
|
25
src/UI/Timeline/PixelCelButton.tscn
Normal file
25
src/UI/Timeline/PixelCelButton.tscn
Normal file
|
@ -0,0 +1,25 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Timeline/BaseCelButton.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://src/UI/Timeline/CelButton.gd" type="Script" id=2]
|
||||
|
||||
[node name="PixelCelButton" instance=ExtResource( 1 )]
|
||||
rect_pivot_offset = Vector2( -18, 6 )
|
||||
script = ExtResource( 2 )
|
||||
|
||||
[node name="PopupMenu" type="PopupMenu" parent="." index="1"]
|
||||
margin_right = 20.0
|
||||
margin_bottom = 20.0
|
||||
mouse_default_cursor_shape = 2
|
||||
items = [ "Delete", null, 0, false, false, -1, 0, null, "", false, "Link Cel", null, 0, false, false, -1, 0, null, "", false ]
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[node name="LinkedIndicator" type="Polygon2D" parent="." index="2"]
|
||||
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="id_pressed" from="PopupMenu" to="." method="_on_PopupMenu_id_pressed"]
|
40
src/UI/Timeline/PixelLayerButton.tscn
Normal file
40
src/UI/Timeline/PixelLayerButton.tscn
Normal file
|
@ -0,0 +1,40 @@
|
|||
[gd_scene load_steps=3 format=2]
|
||||
|
||||
[ext_resource path="res://src/UI/Timeline/BaseLayerButton.tscn" type="PackedScene" id=1]
|
||||
[ext_resource path="res://assets/graphics/layers/unlinked_layer.png" type="Texture" id=4]
|
||||
|
||||
[node name="PixelLayerButton" instance=ExtResource( 1 )]
|
||||
|
||||
[node name="LayerButtons" parent="HBoxContainer" index="1"]
|
||||
margin_right = 122.0
|
||||
|
||||
[node name="LinkButton" type="ToolButton" parent="HBoxContainer/LayerButtons" index="3" groups=["UIButtons"]]
|
||||
margin_left = 96.0
|
||||
margin_top = 7.0
|
||||
margin_right = 118.0
|
||||
margin_bottom = 29.0
|
||||
rect_min_size = Vector2( 22, 22 )
|
||||
hint_tooltip = "Enable/disable cel linking
|
||||
|
||||
Linked cels are being shared across multiple frames"
|
||||
mouse_default_cursor_shape = 2
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 4
|
||||
|
||||
[node name="TextureRect" type="TextureRect" parent="HBoxContainer/LayerButtons/LinkButton" index="0"]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -11.0
|
||||
margin_top = -11.0
|
||||
margin_right = 11.0
|
||||
margin_bottom = 11.0
|
||||
size_flags_horizontal = 0
|
||||
size_flags_vertical = 0
|
||||
texture = ExtResource( 4 )
|
||||
__meta__ = {
|
||||
"_edit_use_anchors_": false
|
||||
}
|
||||
|
||||
[connection signal="pressed" from="HBoxContainer/LayerButtons/LinkButton" to="." method="_on_LinkButton_pressed"]
|
Loading…
Reference in a new issue