From 7f1594e1bc890dc29f8dad59f1aa2c0a23454974 Mon Sep 17 00:00:00 2001
From: Manolis Papadeas <35376950+OverloadedOrama@users.noreply.github.com>
Date: Sat, 30 Jan 2021 23:57:33 +0200
Subject: [PATCH] You can now resize cels in the timeline by holding `Control`
and scrolling with the mouse wheel.
Addresses part of #306
---
CHANGELOG.md | 6 ++-
src/Classes/Project.gd | 13 +++---
src/UI/Timeline/AnimationTagUI.gd | 4 ++
...{AnimationTag.tscn => AnimationTagUI.tscn} | 8 ++--
src/UI/Timeline/AnimationTimeline.gd | 40 ++++++++++++++++++-
src/UI/Timeline/CelButton.gd | 13 ++++++
src/UI/Timeline/CelButton.tscn | 1 +
src/UI/Timeline/LayerButton.gd | 1 +
8 files changed, 75 insertions(+), 11 deletions(-)
create mode 100644 src/UI/Timeline/AnimationTagUI.gd
rename src/UI/Timeline/{AnimationTag.tscn => AnimationTagUI.tscn} (68%)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 157a91059..1c85f9340 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,7 @@ Laurenz Reinthaler (Schweini07), kleonc, Variable-ind
### Added
- A new pan tool, used to move around the canvas. ([#399](https://github.com/Orama-Interactive/Pixelorama/pull/399))
- Dragging and dropping individual cels in the timeline to change their position is now possible.
+- You can now resize cels in the timeline by holding `Control` and scrolling with the mouse wheel.
- Added a new "Performance" tab in the Preferences that exposes options related to the application's FPS to the user.
- Added a new pixel grid, which is a grid of size 1px and it appears after a certain zoom level. ([#427](https://github.com/Orama-Interactive/Pixelorama/pull/427))
- Added offset options to the grid. ([#434](https://github.com/Orama-Interactive/Pixelorama/pull/434))
@@ -28,13 +29,16 @@ Laurenz Reinthaler (Schweini07), kleonc, Variable-ind
- Frame tags can now be set for frames larger than 100. ([#408](https://github.com/Orama-Interactive/Pixelorama/pull/408))
- The "lock aspect ratio" button in the create new image dialog has been changed to a texture button.
- Improved the "Scale Image" dialog. It now automatically sets the size to the current project's size, has a button to lock aspect ratio, and resizing based on percentage.
+- Tile mode rects are now cached for a little speedup. ([#443](https://github.com/Orama-Interactive/Pixelorama/pull/443))
### Fixed
- Fixed layer button textures not being updated properly when changing theme. ([#404](https://github.com/Orama-Interactive/Pixelorama/issues/404))
- Keyboard shortcut conflicts between tool shortcuts and other shortcuts that use the "Control" key, like menu shortcuts, have been resolved. ([#407](https://github.com/Orama-Interactive/Pixelorama/pull/407))
- The opacity of a cel and the tile mode opacity are now multiplicative. ([#414](https://github.com/Orama-Interactive/Pixelorama/pull/414))
- Fixed an issue where adding a new layer did not select it, rather it was selecting the above layer of the previously selected layer. ([#424](https://github.com/Orama-Interactive/Pixelorama/pull/424))
-- Fixed cel opacity not being always updated on the UI. ([#420](https://github.com/Orama-Interactive/Pixelorama/pull/420))
+- Fixed cel opacity not always being updated on the UI. ([#420](https://github.com/Orama-Interactive/Pixelorama/pull/420))
+- Loading empty backuped projects no longer result in a crash. ([#445](https://github.com/Orama-Interactive/Pixelorama/issues/445))
+- Fixed potential index out of bounds error when loading backup files. ([#446](https://github.com/Orama-Interactive/Pixelorama/pull/446))
## [v0.8.2] - 2020-12-12
diff --git a/src/Classes/Project.gd b/src/Classes/Project.gd
index e723abe66..b313c7d62 100644
--- a/src/Classes/Project.gd
+++ b/src/Classes/Project.gd
@@ -127,7 +127,7 @@ func change_project() -> void:
for j in range(frames.size()): # Create frame ID labels
var label := Label.new()
- label.rect_min_size.x = 36
+ label.rect_min_size.x = Global.animation_timeline.cel_size
label.align = Label.ALIGN_CENTER
label.text = str(j + 1)
if j == current_frame:
@@ -383,7 +383,7 @@ func frames_changed(value : Array) -> void:
for j in range(frames.size()):
var label := Label.new()
- label.rect_min_size.x = 36
+ label.rect_min_size.x = Global.animation_timeline.cel_size
label.align = Label.ALIGN_CENTER
label.text = str(j + 1)
Global.frame_ids.add_child(label)
@@ -532,18 +532,19 @@ func animation_tags_changed(value : Array) -> void:
child.queue_free()
for tag in animation_tags:
- var tag_c : Container = load("res://src/UI/Timeline/AnimationTag.tscn").instance()
+ var tag_base_size = Global.animation_timeline.cel_size + 3
+ var tag_c : Container = load("res://src/UI/Timeline/AnimationTagUI.tscn").instance()
Global.tag_container.add_child(tag_c)
+ tag_c.tag = tag
var tag_position : int = Global.tag_container.get_child_count() - 1
Global.tag_container.move_child(tag_c, tag_position)
tag_c.get_node("Label").text = tag.name
tag_c.get_node("Label").modulate = tag.color
tag_c.get_node("Line2D").default_color = tag.color
- tag_c.rect_position.x = (tag.from - 1) * 39 + tag.from
-
+ tag_c.rect_position.x = (tag.from - 1) * tag_base_size + tag.from
var tag_size : int = tag.to - tag.from
- tag_c.rect_min_size.x = (tag_size + 1) * 39
+ tag_c.rect_min_size.x = (tag_size + 1) * tag_base_size
tag_c.get_node("Line2D").points[2] = Vector2(tag_c.rect_min_size.x, 0)
tag_c.get_node("Line2D").points[3] = Vector2(tag_c.rect_min_size.x, 32)
diff --git a/src/UI/Timeline/AnimationTagUI.gd b/src/UI/Timeline/AnimationTagUI.gd
new file mode 100644
index 000000000..2d18c047a
--- /dev/null
+++ b/src/UI/Timeline/AnimationTagUI.gd
@@ -0,0 +1,4 @@
+extends VBoxContainer
+
+
+var tag : AnimationTag
diff --git a/src/UI/Timeline/AnimationTag.tscn b/src/UI/Timeline/AnimationTagUI.tscn
similarity index 68%
rename from src/UI/Timeline/AnimationTag.tscn
rename to src/UI/Timeline/AnimationTagUI.tscn
index 8265c8435..b1b1504f4 100644
--- a/src/UI/Timeline/AnimationTag.tscn
+++ b/src/UI/Timeline/AnimationTagUI.tscn
@@ -1,9 +1,12 @@
-[gd_scene format=2]
+[gd_scene load_steps=2 format=2]
-[node name="AnimationTag" type="VBoxContainer"]
+[ext_resource path="res://src/UI/Timeline/AnimationTagUI.gd" type="Script" id=1]
+
+[node name="AnimationTagUI" type="VBoxContainer"]
margin_right = 39.0
margin_bottom = 32.0
rect_min_size = Vector2( 39, 32 )
+script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
@@ -11,7 +14,6 @@ __meta__ = {
[node name="Line2D" type="Line2D" parent="."]
points = PoolVector2Array( 0, 32, 0, 0, 39, 0, 39, 32 )
width = 1.0
-texture_mode = 1313163520
[node name="Label" type="Label" parent="."]
margin_left = 7.0
diff --git a/src/UI/Timeline/AnimationTimeline.gd b/src/UI/Timeline/AnimationTimeline.gd
index 468f996bc..df064d2d2 100644
--- a/src/UI/Timeline/AnimationTimeline.gd
+++ b/src/UI/Timeline/AnimationTimeline.gd
@@ -4,6 +4,10 @@ var animation_loop := 1 # 0 is no loop, 1 is cycle loop, 2 is ping-pong loop
var animation_forward := true
var first_frame := 0
var last_frame := 0
+var is_mouse_hover := false
+var cel_size := 36 setget cel_size_changed
+var min_cel_size := 36
+var max_cel_size := 144
var timeline_scroll : ScrollContainer
var tag_scroll_container : ScrollContainer
@@ -20,12 +24,47 @@ func _ready() -> void:
fps_spinbox.value = Global.current_project.fps
+func _input(event : InputEvent) -> void:
+ var mouse_pos := get_global_mouse_position()
+ var timeline_rect := Rect2(rect_global_position, rect_size)
+ if timeline_rect.has_point(mouse_pos):
+ if Input.is_key_pressed(KEY_CONTROL):
+ self.cel_size += (2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out")))
+
+
func _h_scroll_changed(value : float) -> void:
# Let the main timeline ScrollContainer affect the tag ScrollContainer too
tag_scroll_container.get_child(0).rect_min_size.x = timeline_scroll.get_child(0).rect_size.x - 212
tag_scroll_container.scroll_horizontal = value
+func cel_size_changed(value : int) -> void:
+ cel_size = clamp(value, min_cel_size, max_cel_size)
+ for layer_button in Global.layers_container.get_children():
+ layer_button.rect_min_size.y = cel_size
+ layer_button.rect_size.y = cel_size
+ for layer in Global.current_project.layers:
+ for cel_button in layer.frame_container.get_children():
+ cel_button.rect_min_size.x = cel_size
+ cel_button.rect_min_size.y = cel_size
+ cel_button.rect_size.x = cel_size
+ cel_button.rect_size.y = cel_size
+
+ for frame_id in Global.frame_ids.get_children():
+ frame_id.rect_min_size.x = cel_size
+ frame_id.rect_size.x = cel_size
+
+ for tag_c in Global.tag_container.get_children():
+ var tag_base_size = cel_size + 3
+ var tag : AnimationTag = tag_c.tag
+ tag_c.rect_position.x = (tag.from - 1) * tag_base_size + tag.from
+ var tag_size : int = tag.to - tag.from
+ tag_c.rect_min_size.x = (tag_size + 1) * tag_base_size
+ tag_c.rect_size.x = (tag_size + 1) * tag_base_size
+ tag_c.get_node("Line2D").points[2] = Vector2(tag_c.rect_min_size.x, 0)
+ tag_c.get_node("Line2D").points[3] = Vector2(tag_c.rect_min_size.x, 32)
+
+
func add_frame() -> void:
var frame : Frame = Global.canvas.new_empty_frame()
var new_frames : Array = Global.current_project.frames.duplicate()
@@ -502,4 +541,3 @@ func _on_OpacitySlider_value_changed(value) -> void:
func _on_OnionSkinningSettings_popup_hide() -> void:
Global.can_draw = true
-
diff --git a/src/UI/Timeline/CelButton.gd b/src/UI/Timeline/CelButton.gd
index a8373642f..fa2f311bd 100644
--- a/src/UI/Timeline/CelButton.gd
+++ b/src/UI/Timeline/CelButton.gd
@@ -7,6 +7,9 @@ onready var popup_menu : PopupMenu = $PopupMenu
func _ready() -> void:
+ rect_min_size.x = Global.animation_timeline.cel_size
+ 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
@@ -22,6 +25,16 @@ func _ready() -> void:
checker.rect_size = checker.get_parent().rect_size
+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
+
+
func _on_CelButton_pressed() -> void:
if Input.is_action_just_released("left_mouse"):
Global.current_project.current_frame = frame
diff --git a/src/UI/Timeline/CelButton.tscn b/src/UI/Timeline/CelButton.tscn
index 3ec82579b..996879970 100644
--- a/src/UI/Timeline/CelButton.tscn
+++ b/src/UI/Timeline/CelButton.tscn
@@ -67,4 +67,5 @@ 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"]
diff --git a/src/UI/Timeline/LayerButton.gd b/src/UI/Timeline/LayerButton.gd
index 2ef61a905..c8d32e76e 100644
--- a/src/UI/Timeline/LayerButton.gd
+++ b/src/UI/Timeline/LayerButton.gd
@@ -11,6 +11,7 @@ var line_edit : LineEdit
func _ready() -> void:
+ rect_min_size.y = Global.animation_timeline.cel_size
visibility_button = find_node("VisibilityButton")
lock_button = find_node("LockButton")
linked_button = find_node("LinkButton")