From 5781c4282188b3c8638797d459e97d841c237237 Mon Sep 17 00:00:00 2001 From: OverloadedOrama <35376950+OverloadedOrama@users.noreply.github.com> Date: Tue, 10 Sep 2019 01:57:46 +0300 Subject: [PATCH] v0.2 - Animation Timeline & UI changes! v0.2 of Pixelorama is out! - Added animation timeline. You can add. remove. clone and change order of your frames! - You can now import multiple images as frames. - Ability to save individual frames, all frames as multiple files, or all frames as a single file in the form of a horizontal or vertical spritesheet! - Different frames can have a unique amount of layers and they can be of different sizes. - Image scaling is now functional. - Added hints for UI elements. - A lot of UI changes. --- .gitignore | 3 +- .../.png-05675a12d3f10112da9382ffea612140.md5 | 3 - ...r.png-13de7b2e25322c0fe05acb73bde7971f.md5 | 3 - ....png-13de7b2e25322c0fe05acb73bde7971f.stex | Bin 23790 -> 0 bytes ...0.png-01fadc6686974ab1f9d994c50d1e42a1.md5 | 3 - ...0.png-a6b83c75a67b83f874e6120982b6723d.md5 | 3 - ....png-a6b83c75a67b83f874e6120982b6723d.stex | Bin 2282 -> 0 bytes ....png-b5955c8e7e6eaecd8f24a1732239745d.stex | Bin 112 -> 0 bytes ...e.png-cba7a0d7dc311bf5109856c071223323.md5 | 3 - ....png-643b5c8878aaf0c84a360796789dae22.stex | Bin 111 -> 0 bytes ...o.png-e103c16b45db77894c95005feb7fad3f.md5 | 3 - ...o.png-32d3b5843c98359b9557fafcc551e353.md5 | 3 - ...k.png-436d9a0bf8e96a20d85e9c9482696318.md5 | 3 - ...o.png-987fe23e74877197b78dca2a42501332.md5 | 3 - ...n.png-0306dc70550a8aeeafa7b550dccd1b4a.md5 | 3 - ...y.png-3d5a982cb56eb81a92736b42a51d4a5b.md5 | 3 - ...y.png-6cdc85baf6ec3016cd63aa20e3a024a2.md5 | 3 - FrameButton.tscn | 34 ++ Main.tscn | 308 +++++++++++--- Scripts/CameraMovement.gd | 12 +- Scripts/Canvas.gd | 108 +++-- Scripts/FrameButton.gd | 8 + Scripts/Global.gd | 59 ++- Scripts/Main.gd | 376 +++++++++++++++--- export_presets.cfg | 4 +- 25 files changed, 765 insertions(+), 183 deletions(-) delete mode 100644 .import/.png-05675a12d3f10112da9382ffea612140.md5 delete mode 100644 .import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.md5 delete mode 100644 .import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.stex delete mode 100644 .import/Transparency500.png-01fadc6686974ab1f9d994c50d1e42a1.md5 delete mode 100644 .import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.md5 delete mode 100644 .import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.stex delete mode 100644 .import/Transparent Background.png-b5955c8e7e6eaecd8f24a1732239745d.stex delete mode 100644 .import/eraser-outline.png-cba7a0d7dc311bf5109856c071223323.md5 delete mode 100644 .import/grid.png-643b5c8878aaf0c84a360796789dae22.stex delete mode 100644 .import/hello.png-e103c16b45db77894c95005feb7fad3f.md5 delete mode 100644 .import/o.png-32d3b5843c98359b9557fafcc551e353.md5 delete mode 100644 .import/ok.png-436d9a0bf8e96a20d85e9c9482696318.md5 delete mode 100644 .import/ooo.png-987fe23e74877197b78dca2a42501332.md5 delete mode 100644 .import/pencil-striped-outlined-tool-in-diagonal-position.png-0306dc70550a8aeeafa7b550dccd1b4a.md5 delete mode 100644 .import/strelitzia baby.png-3d5a982cb56eb81a92736b42a51d4a5b.md5 delete mode 100644 .import/yy.png-6cdc85baf6ec3016cd63aa20e3a024a2.md5 create mode 100644 FrameButton.tscn create mode 100644 Scripts/FrameButton.gd diff --git a/.gitignore b/.gitignore index 245ddbb1d..d69a443a3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -Scripts/Old/ \ No newline at end of file +Scripts/Old/ +Assets/Graphics/Tools/ \ No newline at end of file diff --git a/.import/.png-05675a12d3f10112da9382ffea612140.md5 b/.import/.png-05675a12d3f10112da9382ffea612140.md5 deleted file mode 100644 index 7f0c11ab1..000000000 --- a/.import/.png-05675a12d3f10112da9382ffea612140.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="b8469a8d2b9b7f33cde9c50c882514d3" -dest_md5="611bf34048e600d74fb53c849097c026" - diff --git a/.import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.md5 b/.import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.md5 deleted file mode 100644 index 91a5f1f3b..000000000 --- a/.import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="3f3e12abce4c2177df141c708b02c3cc" -dest_md5="5bb71e82d18a6514c7bec6e2f2996585" - diff --git a/.import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.stex b/.import/Sprite Editor.png-13de7b2e25322c0fe05acb73bde7971f.stex deleted file mode 100644 index 3259978668934f1a930148b351f08e7d5e7f997b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23790 zcmeGEXEa>xA2tkcB$3F4B#2%!>IBhyNkkcfD5H!ZiRe9gmx2^^1R+Yq=!Phxw<{7P z`d~yGA%fAxFbu=9UH^Nn_tX33`S`4R*0T57W7}u@mE$;m=caqt%$$z~0IaA1;2d!F zxk5_?96gsq(R7N*G4xhzjH^avdBXf)M{AZg3HcKn@ zNg-<<-3TbyI&krM#@boO07aiGnrG*8u>d#>fbZ71D`%I__@mEG7yqF;8=2hK(I|4`yH9CSN2M2`4Y@o-_19CLm5VT zS;dPs$p5ulg6fFt*a`~w1T=G{a8nN^sDNZ{2S|<(;U>&kugrKsDo9Vc$5-v-CZP?M zJ#mwu4hw>XYGT!Uz*ZKiz_1oC!Gau2_kWEtW8rX1D@$crP4k(50!u>eG}^%!VPrH) zg=JNo3W%o$1Eol~4)zjK9YS~z6RNIL*MioS^qMSZr-v)Mga;69heTxWLPs^O=;Sx? z^yn~D%#BwX8ge5P11h@5-wE0bs>2#YnRR%A?n?ri3|BRQk3MO7p-HGH6Z0DyDG|02 zi0XWpWNWqM*+aRHngwCI!V{}ymlKif;pFp3uYu2zta{{##n?1rjE%)=nkO2GdhPH7 z!ZiV^=r3kaf&)?=>N@2k>@_!0SUjOX zAWVE94h@9K{pvZ*Io%85En`|ve5+n}8yj9Y*DIMye1o!1p-F0MwwY@?`qL=Pd4pTE zUFWT{g3Hcr`Yf4zC)8gB1M+JWCj?VutqYC^%nctuw_0MWSP<4?l}m|sYR!QeJP+E; zsx~|f%7$SMV*V7}L^y2Z<3@hF2%$`N?eIKIBXMShgjV1A;9Q3hY%1j%sHu(v&dpcl2QPW_O6A-xzsj7uMkr>l~X#GO81e()F{ow3FC51xnu#^uta{!nHW+W8Ob5XTu^0h$ zbjkL})Oc}=rDuS7i$Y)clYz>gUF#nifb-8m&x&yvj{mFJl`M@LRruIZF>@{KV3*F* zhixGBvE?Sb@D9{(BdEvEW^7#HS6!m%%rbuSSOAEw;EM({=h>Jw#cHl-LI{;`n{m8M ziPodmJ6#?1VzN?g#@OgPYSIz&4mOZBHg!wn*yMCoOJ30Q(Nz;`eb5T;XoH6@QY9(2 zQgv51@9G+NY(_k?S)ZRo3PJ0>zj552wEUe_G&nW<$z^se}cb8mL^u zd!xsF%0=*`g+RF=qEmqz67?6!AJxwG{5){}aj&i(5Zx-*NDFyObr*TkxIn+*wSlXw z=h<-Ez-`v^>=7AD%7Zj%B1OWPLv&aQwZ)(k*v2gBgeviggDh#an!sK$xDkAqh8j5k z_P@!sCnjXo@N<4r!4#u)qe26BKQI4tV6ibvakK2mnhL9P3agopc~aCI-kVnyu`@^m zEb_)aq|%)K$rDkK-z;mn*W1*+TJuxub3{cG#ih+#GP=a1h2K$W@9coRB?LHP@rYy}LjcS{(Ni36FMMm zVuUVz3TYFDv`h9cef*`Ty|SHh96`nf#cM6P6)LtW_5MCZHB$_rX$-qL)8$ zkFG5?&vZo&ZB*L~M6)?H=6Fy6FldT@25MASaZ4L!pF*6tItWc8+QRJb-*c%(@*vu@ zCNyg7&{~`ev@cg{9^2OW7Y!n0wR5GagN~4qHwm0bovB1h4lTC%m(V)$8O17%Co)>-DHG@=%)_-ok1=M$Sz%&U&`jKaW^k1Ic*Rs8|nz{lYT zV=T)EEpEeObUCualtN?SCp1>l%ZYuTBSuyRuI;_@$RH}gMw!Xxk;BR5Ip|q()e&yxn|N5Q$*GCM{8%*^%f2g{AJ`inWuO23 z&osnV+|_jb5)Pr(7+QQndYy1Yga7%%)HdQ@0YeU(t6}6g!P&(|GT_sB7Cgv_mMf#% z6yDT^z&*llLj@L$uKdEr-X+*?2F|Nrn|>qPJ7uaA2)ZP+i4EzQ(!>pTTH!bH7ebuN zWcFfIcey-f#WJaKf^55?wfRA|=#Hgrqh3JTi+yf_h06+Vl-+_AV9)~tx!w>n49dLc z8X7bg-F_Umytg`7|A@EIMJK0HF(9#M3@)VF(_o>X)_%J|jdFpB!So5_EEq?)OjZOl zjgh9Ou%&rwjYdNqBhnrre!{pF-DU35nt#KRJj`5pE^+cvYrX+pExDNv*2m%&txq>F za&V$nzPB=E3uC#DSSPgpE?PVOT~v;8+5XYWtwtda&PuwE7tM2av*ACn2aw4vjPQVd zr-TTa_LJ>?PIA|%cZqkWaalzwBYRa-?8qm821_0BbHdK-}Z{wd* z!)C$`y(p_}h(}Ci@bm+2xdJ2P*ciURdv@pX%)F-FY<#R(#8Gw(2X8Lx--Yxx^5mS| zIOl*?TyMhSjXtNf<8Px5jP}BWzwuByfc6TAfKW>hV$yqOw@UX6$s`qf^X3kt1e6); zy|HPAoR7S-4LXJ!YB$s`e0MLA812ZGGG;{MOKI)#Df`Lt4k+kc?R^jwe8ulY!Wx_{ z4F1P2`9fp_(WWkxU+&o+0K?R6- zg8Fv(pPdY^Z!7h_#&KTZ>w7=DdSGOIhB6x9d>rW3H*EL_?|Ll?!`Tup746zk*J^kl*?5ebF zD0Y2j{9?$T0^uQCV^+P%*sb`ansaNkFnBL!P{a zGncy3{x%~^=n(L~`+6(i)hR#i(j)gzFO^lGM4Vafc%`K=6Lz;0?>cSIW037RsdQAD zRA6%H>;+e?eC#|!{bS}e&i?yWrMvjU7yc`k#+wwk{&B}KU-Qrgc(kkur=4QZeqC=U3oC; zH#LRLY(enfO6@jZ$$Fb)G5#xU7^kPKvrYl?P(CgA^a*|f%^MCUGZO?VDq

g>`4m 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 diff --git a/.import/Transparency500.png-01fadc6686974ab1f9d994c50d1e42a1.md5 b/.import/Transparency500.png-01fadc6686974ab1f9d994c50d1e42a1.md5 deleted file mode 100644 index 2d466955e..000000000 --- a/.import/Transparency500.png-01fadc6686974ab1f9d994c50d1e42a1.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="90f1e764a9d0303186411784568ef237" -dest_md5="b40997122ed6d10d1612023e114c7315" - diff --git a/.import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.md5 b/.import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.md5 deleted file mode 100644 index 2c9cc5680..000000000 --- a/.import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="90f1e764a9d0303186411784568ef237" -dest_md5="5d2507d2ac9dd6d7f8b781cd64e5e4b6" - diff --git a/.import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.stex b/.import/Transparency500.png-a6b83c75a67b83f874e6120982b6723d.stex deleted file mode 100644 index eb3a718657196f4da91b25577fa85b84f91e00cc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2282 zcmZ>F2@d(f$iM)?EDRtZzz$?Goa10%2=H@P=mZkHTvA*>Azn`pmmmfP#xEeu!2}d> z+2V1Rfq`S9r;B4q#hka-4sxnk3b-D8xlmT?$$sX;U7I{M=sj_4eF2@YXmU|;}Y2oPXr1TsQ^IKatA!B!jmu*Z%5r+vfw7FnGH9xvXF2@YXqU|;}Y79eI|5MXBnlEFY6;ODN;2_$&Aq_}`wUQZ8~ARrA^&cOy`g=uWv x52VCAT^vI=W+ta3B>Xtf!0Hn)OVI5=DuYfb6N{~(;WnTO22WQ%mvv4FO#oD86kGrR diff --git a/.import/hello.png-e103c16b45db77894c95005feb7fad3f.md5 b/.import/hello.png-e103c16b45db77894c95005feb7fad3f.md5 deleted file mode 100644 index 436041223..000000000 --- a/.import/hello.png-e103c16b45db77894c95005feb7fad3f.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="327bd47a99785cc67d3b563e11e15386" -dest_md5="f762a141beffeb685bedf56872c571fc" - diff --git a/.import/o.png-32d3b5843c98359b9557fafcc551e353.md5 b/.import/o.png-32d3b5843c98359b9557fafcc551e353.md5 deleted file mode 100644 index 2bd01ac08..000000000 --- a/.import/o.png-32d3b5843c98359b9557fafcc551e353.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="3b9968d48bb94408d74340e812e4a715" -dest_md5="2d008139a38b2c0df1d773b0eb202d2f" - diff --git a/.import/ok.png-436d9a0bf8e96a20d85e9c9482696318.md5 b/.import/ok.png-436d9a0bf8e96a20d85e9c9482696318.md5 deleted file mode 100644 index 644dd459c..000000000 --- a/.import/ok.png-436d9a0bf8e96a20d85e9c9482696318.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="d0ec0d56b87c9a8c60688d6af9d226a0" -dest_md5="605f5c73c93dc2a072713c6f3fcd0563" - diff --git a/.import/ooo.png-987fe23e74877197b78dca2a42501332.md5 b/.import/ooo.png-987fe23e74877197b78dca2a42501332.md5 deleted file mode 100644 index 0c29490e8..000000000 --- a/.import/ooo.png-987fe23e74877197b78dca2a42501332.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="1afa25ff3984b4aa5d235e151ea745f2" -dest_md5="3331184ae61337c572353772eeedb37b" - diff --git a/.import/pencil-striped-outlined-tool-in-diagonal-position.png-0306dc70550a8aeeafa7b550dccd1b4a.md5 b/.import/pencil-striped-outlined-tool-in-diagonal-position.png-0306dc70550a8aeeafa7b550dccd1b4a.md5 deleted file mode 100644 index e4a59f740..000000000 --- a/.import/pencil-striped-outlined-tool-in-diagonal-position.png-0306dc70550a8aeeafa7b550dccd1b4a.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="8cc6a8f03f20c923403c7d96eb234a23" -dest_md5="b99e77f302c757ba661cafd4fec3bab0" - diff --git a/.import/strelitzia baby.png-3d5a982cb56eb81a92736b42a51d4a5b.md5 b/.import/strelitzia baby.png-3d5a982cb56eb81a92736b42a51d4a5b.md5 deleted file mode 100644 index 3847bcd04..000000000 --- a/.import/strelitzia baby.png-3d5a982cb56eb81a92736b42a51d4a5b.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="16bf0d760b5c4ff30efd2a7ddb10c5a7" -dest_md5="c9a9e4d828f496f7c9371c42dd41c332" - diff --git a/.import/yy.png-6cdc85baf6ec3016cd63aa20e3a024a2.md5 b/.import/yy.png-6cdc85baf6ec3016cd63aa20e3a024a2.md5 deleted file mode 100644 index 1b0bac548..000000000 --- a/.import/yy.png-6cdc85baf6ec3016cd63aa20e3a024a2.md5 +++ /dev/null @@ -1,3 +0,0 @@ -source_md5="702bfdd94a8185490af255dd080e549d" -dest_md5="0944e37fba7b57fbcd1c1b699eddb31f" - diff --git a/FrameButton.tscn b/FrameButton.tscn new file mode 100644 index 000000000..21047560b --- /dev/null +++ b/FrameButton.tscn @@ -0,0 +1,34 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://Scripts/FrameButton.gd" type="Script" id=1] + +[node name="Frame" type="VBoxContainer"] +margin_right = 32.0 +margin_bottom = 50.0 + +[node name="FrameButton" type="Button" parent="."] +margin_right = 36.0 +margin_bottom = 36.0 +rect_min_size = Vector2( 36, 36 ) +mouse_default_cursor_shape = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +script = ExtResource( 1 ) + +[node name="FrameTexture" type="TextureRect" parent="FrameButton"] +margin_left = 2.0 +margin_top = 2.0 +margin_right = 34.0 +margin_bottom = 34.0 +rect_min_size = Vector2( 32, 32 ) +size_flags_horizontal = 0 +size_flags_vertical = 0 +expand = true + +[node name="FrameID" type="Label" parent="."] +margin_top = 40.0 +margin_right = 36.0 +margin_bottom = 54.0 +text = "0" +align = 1 +[connection signal="pressed" from="FrameButton" to="FrameButton" method="_on_FrameButton_pressed"] diff --git a/Main.tscn b/Main.tscn index 3b29a904b..2b9718524 100644 --- a/Main.tscn +++ b/Main.tscn @@ -211,27 +211,163 @@ min_value = 1.0 value = 1.0 suffix = "px" -[node name="ViewportContainer" type="ViewportContainer" parent="UI"] -editor/display_folded = true +[node name="CanvasAndTimeline" type="VBoxContainer" parent="UI"] margin_left = 324.0 margin_right = 860.0 margin_bottom = 600.0 +size_flags_horizontal = 3 + +[node name="ViewportContainer" type="ViewportContainer" parent="UI/CanvasAndTimeline"] +margin_right = 536.0 +margin_bottom = 448.0 mouse_default_cursor_shape = 3 size_flags_horizontal = 3 +size_flags_vertical = 3 stretch = true -[node name="Viewport" type="Viewport" parent="UI/ViewportContainer"] -size = Vector2( 536, 600 ) +[node name="Viewport" type="Viewport" parent="UI/CanvasAndTimeline/ViewportContainer"] +size = Vector2( 536, 448 ) handle_input_locally = false render_target_update_mode = 3 -[node name="Canvas" parent="UI/ViewportContainer/Viewport" instance=ExtResource( 5 )] +[node name="Canvas" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport" instance=ExtResource( 5 )] -[node name="Camera2D" type="Camera2D" parent="UI/ViewportContainer/Viewport"] +[node name="Camera2D" type="Camera2D" parent="UI/CanvasAndTimeline/ViewportContainer/Viewport"] current = true zoom = Vector2( 0.15, 0.15 ) script = ExtResource( 6 ) +[node name="AnimationTimeline" type="Panel" parent="UI/CanvasAndTimeline"] +margin_top = 452.0 +margin_right = 536.0 +margin_bottom = 600.0 +rect_min_size = Vector2( 0, 148 ) +size_flags_horizontal = 3 + +[node name="TimelineContainer" type="VBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 + +[node name="ButtonContainer" type="CenterContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"] +margin_right = 536.0 +margin_bottom = 40.0 + +[node name="AnimationButtons" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer"] +margin_left = 69.0 +margin_right = 467.0 +margin_bottom = 40.0 + +[node name="LoopAnim" type="CheckButton" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"] +margin_right = 111.0 +margin_bottom = 40.0 +hint_tooltip = "Should the animation loop (play again after it reached the end)?" +mouse_default_cursor_shape = 2 +text = "Loop" + +[node name="PlayBackwards" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"] +margin_left = 115.0 +margin_right = 224.0 +margin_bottom = 40.0 +hint_tooltip = "Play the animation backwards (from end to beggining)" +mouse_default_cursor_shape = 2 +toggle_mode = true +text = "Play Backwards" + +[node name="PlayForward" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"] +margin_left = 228.0 +margin_right = 320.0 +margin_bottom = 40.0 +hint_tooltip = "Play the animation forward (from beggining to end)" +mouse_default_cursor_shape = 2 +size_flags_horizontal = 0 +toggle_mode = true +text = "Play Forward" + +[node name="FPSValue" type="SpinBox" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons"] +margin_left = 324.0 +margin_right = 398.0 +margin_bottom = 40.0 +hint_tooltip = "How many frames per second should the animation preview be? The more FPS, the faster the animation plays." +mouse_default_cursor_shape = 2 +min_value = 1.0 +value = 1.0 +suffix = "FPS" + +[node name="HSeparator" type="HSeparator" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"] +margin_top = 44.0 +margin_right = 536.0 +margin_bottom = 48.0 + +[node name="CenterContainer" type="CenterContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"] +margin_top = 52.0 +margin_right = 536.0 +margin_bottom = 72.0 + +[node name="FrameButtons" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer"] +margin_left = 209.0 +margin_right = 326.0 +margin_bottom = 20.0 + +[node name="AddFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"] +margin_right = 20.0 +margin_bottom = 20.0 +hint_tooltip = "Add a new frame" +mouse_default_cursor_shape = 2 +size_flags_horizontal = 0 +text = "+" + +[node name="RemoveFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"] +margin_left = 24.0 +margin_right = 41.0 +margin_bottom = 20.0 +hint_tooltip = "Remove selected frame" +mouse_default_cursor_shape = 8 +disabled = true +text = "-" + +[node name="MoveFrameLeft" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"] +margin_left = 45.0 +margin_right = 65.0 +margin_bottom = 20.0 +hint_tooltip = "Move selected frame to the left" +mouse_default_cursor_shape = 8 +disabled = true +text = "<" + +[node name="MoveFrameRight" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"] +margin_left = 69.0 +margin_right = 89.0 +margin_bottom = 20.0 +hint_tooltip = "Move selected frame to the right" +mouse_default_cursor_shape = 8 +disabled = true +text = ">" + +[node name="CloneFrame" type="Button" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons"] +margin_left = 93.0 +margin_right = 117.0 +margin_bottom = 20.0 +hint_tooltip = "Clone current frame" +mouse_default_cursor_shape = 2 +size_flags_horizontal = 0 +text = "Cl" + +[node name="HSeparator2" type="HSeparator" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"] +margin_top = 76.0 +margin_right = 536.0 +margin_bottom = 80.0 + +[node name="ScrollContainer" type="ScrollContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer"] +margin_top = 84.0 +margin_right = 536.0 +margin_bottom = 148.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +scroll_vertical_enabled = false + +[node name="FrameContainer" type="HBoxContainer" parent="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ScrollContainer"] + [node name="LayerPanel" type="Panel" parent="UI"] editor/display_folded = true margin_left = 864.0 @@ -239,19 +375,22 @@ margin_right = 1024.0 margin_bottom = 600.0 rect_min_size = Vector2( 160, 0 ) -[node name="ScrollContainer" type="ScrollContainer" parent="UI/LayerPanel"] -editor/display_folded = true +[node name="LayersAndMisc" type="VBoxContainer" parent="UI/LayerPanel"] +anchor_right = 1.0 +anchor_bottom = 1.0 + +[node name="ScrollContainer" type="ScrollContainer" parent="UI/LayerPanel/LayersAndMisc"] margin_right = 160.0 -margin_bottom = 600.0 +margin_bottom = 538.0 size_flags_horizontal = 3 size_flags_vertical = 3 -[node name="VBoxLayerContainer" type="VBoxContainer" parent="UI/LayerPanel/ScrollContainer"] +[node name="VBoxLayerContainer" type="VBoxContainer" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer"] margin_right = 160.0 margin_bottom = 38.0 size_flags_horizontal = 3 -[node name="LayerLabel" type="Label" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer"] +[node name="LayerLabel" type="Label" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer"] margin_right = 160.0 margin_bottom = 14.0 size_flags_horizontal = 3 @@ -259,19 +398,25 @@ size_flags_vertical = 0 text = "Layers" align = 1 -[node name="HBoxContainer" type="HBoxContainer" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer"] +[node name="CenterContainer" type="CenterContainer" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer"] +editor/display_folded = true margin_top = 18.0 margin_right = 160.0 margin_bottom = 38.0 -[node name="AddLayerButton" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] +[node name="LayerButtons" type="HBoxContainer" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer"] +margin_left = 7.0 +margin_right = 153.0 +margin_bottom = 20.0 + +[node name="AddLayerButton" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"] margin_right = 20.0 margin_bottom = 20.0 hint_tooltip = "Create a new layer" mouse_default_cursor_shape = 2 text = "+" -[node name="RemoveLayerButton" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] +[node name="RemoveLayerButton" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"] margin_left = 24.0 margin_right = 44.0 margin_bottom = 20.0 @@ -280,7 +425,7 @@ mouse_default_cursor_shape = 8 disabled = true text = "X" -[node name="MoveUpLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] +[node name="MoveUpLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"] margin_left = 48.0 margin_right = 67.0 margin_bottom = 20.0 @@ -289,7 +434,7 @@ mouse_default_cursor_shape = 8 disabled = true text = "^" -[node name="MoveDownLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] +[node name="MoveDownLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"] margin_left = 71.0 margin_right = 90.0 margin_bottom = 20.0 @@ -298,7 +443,7 @@ mouse_default_cursor_shape = 8 disabled = true text = "v" -[node name="CloneLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] +[node name="CloneLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"] margin_left = 94.0 margin_right = 118.0 margin_bottom = 20.0 @@ -306,7 +451,7 @@ hint_tooltip = "Clone current layer" mouse_default_cursor_shape = 2 text = "Cl" -[node name="MergeDownLayer" type="Button" parent="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer"] +[node name="MergeDownLayer" type="Button" parent="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons"] margin_left = 122.0 margin_right = 146.0 margin_bottom = 20.0 @@ -315,6 +460,28 @@ mouse_default_cursor_shape = 8 disabled = true text = "M" +[node name="HSeparator" type="HSeparator" parent="UI/LayerPanel/LayersAndMisc"] +margin_top = 542.0 +margin_right = 160.0 +margin_bottom = 546.0 + +[node name="CursorPosition" type="Label" parent="UI/LayerPanel/LayersAndMisc"] +margin_top = 550.0 +margin_right = 160.0 +margin_bottom = 564.0 +text = "[64x64]" + +[node name="ZoomLevel" type="Label" parent="UI/LayerPanel/LayersAndMisc"] +margin_top = 568.0 +margin_right = 160.0 +margin_bottom = 582.0 +text = "Zoom: x7.81" + +[node name="EmptyLabel" type="Label" parent="UI/LayerPanel/LayersAndMisc"] +margin_top = 586.0 +margin_right = 160.0 +margin_bottom = 600.0 + [node name="CreateNewImage" type="ConfirmationDialog" parent="."] editor/display_folded = true margin_right = 200.0 @@ -342,11 +509,14 @@ margin_right = 46.0 margin_bottom = 19.0 text = "Width: " -[node name="LineEdit" type="LineEdit" parent="CreateNewImage/VBoxContainer/WidthCont"] +[node name="WidthValue" type="SpinBox" parent="CreateNewImage/VBoxContainer/WidthCont"] margin_left = 50.0 -margin_right = 108.0 +margin_right = 124.0 margin_bottom = 24.0 -text = "64" +min_value = 1.0 +max_value = 16384.0 +value = 64.0 +suffix = "px" [node name="HeightCont" type="HBoxContainer" parent="CreateNewImage/VBoxContainer"] margin_top = 46.0 @@ -359,18 +529,21 @@ margin_right = 46.0 margin_bottom = 19.0 text = "Height:" -[node name="LineEdit" type="LineEdit" parent="CreateNewImage/VBoxContainer/HeightCont"] +[node name="HeightValue" type="SpinBox" parent="CreateNewImage/VBoxContainer/HeightCont"] margin_left = 50.0 -margin_right = 108.0 +margin_right = 124.0 margin_bottom = 24.0 -text = "64" +min_value = 1.0 +max_value = 16384.0 +value = 64.0 +suffix = "px" [node name="OpenSprite" type="FileDialog" parent="."] margin_right = 515.0 margin_bottom = 348.0 -window_title = "Open a File" +window_title = "Open File(s)" resizable = true -mode = 0 +mode = 1 access = 2 filters = PoolStringArray( "*jpg, *.png ; JPG, PNG Images" ) current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama" @@ -385,7 +558,7 @@ margin_left = -512.0 margin_top = -300.0 margin_right = 3.0 margin_bottom = 48.0 -window_title = "Create a new image" +window_title = "Export sprite" resizable = true access = 2 filters = PoolStringArray( "*.png ; PNG Image" ) @@ -393,24 +566,25 @@ current_dir = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικ current_path = "C:/Users/Overloaded/Dropbox/Orama Founding Members/εταιρικα αρχεια/Godot Projects/Pixelorama/" [node name="ScaleImage" type="ConfirmationDialog" parent="."] -editor/display_folded = true +visible = true margin_right = 200.0 margin_bottom = 114.0 [node name="VBoxContainer" type="VBoxContainer" parent="ScaleImage"] margin_left = 8.0 margin_top = 8.0 -margin_right = 192.0 -margin_bottom = 78.0 +margin_right = 257.0 +margin_bottom = 102.0 [node name="ImageSize" type="Label" parent="ScaleImage/VBoxContainer"] -margin_right = 184.0 +margin_right = 249.0 margin_bottom = 14.0 text = "Image Size" [node name="WidthCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"] +editor/display_folded = true margin_top = 18.0 -margin_right = 184.0 +margin_right = 249.0 margin_bottom = 42.0 [node name="WidthLabel" type="Label" parent="ScaleImage/VBoxContainer/WidthCont"] @@ -419,15 +593,19 @@ margin_right = 46.0 margin_bottom = 19.0 text = "Width: " -[node name="LineEdit" type="LineEdit" parent="ScaleImage/VBoxContainer/WidthCont"] +[node name="WidthValue" type="SpinBox" parent="ScaleImage/VBoxContainer/WidthCont"] margin_left = 50.0 -margin_right = 108.0 +margin_right = 124.0 margin_bottom = 24.0 -text = "64" +min_value = 1.0 +max_value = 16384.0 +value = 64.0 +suffix = "px" [node name="HeightCont" type="HBoxContainer" parent="ScaleImage/VBoxContainer"] +editor/display_folded = true margin_top = 46.0 -margin_right = 184.0 +margin_right = 249.0 margin_bottom = 70.0 [node name="Height" type="Label" parent="ScaleImage/VBoxContainer/HeightCont"] @@ -436,11 +614,35 @@ margin_right = 46.0 margin_bottom = 19.0 text = "Height:" -[node name="LineEdit" type="LineEdit" parent="ScaleImage/VBoxContainer/HeightCont"] +[node name="HeightValue" type="SpinBox" parent="ScaleImage/VBoxContainer/HeightCont"] margin_left = 50.0 -margin_right = 108.0 +margin_right = 124.0 margin_bottom = 24.0 -text = "64" +min_value = 1.0 +max_value = 16384.0 +value = 64.0 +suffix = "px" + +[node name="InterpolationContainer" type="HBoxContainer" parent="ScaleImage/VBoxContainer"] +margin_top = 74.0 +margin_right = 249.0 +margin_bottom = 94.0 + +[node name="InterpolationLabel" type="Label" parent="ScaleImage/VBoxContainer/InterpolationContainer"] +margin_top = 3.0 +margin_right = 87.0 +margin_bottom = 17.0 +text = "Interpolation:" + +[node name="InterpolationType" type="OptionButton" parent="ScaleImage/VBoxContainer/InterpolationContainer"] +margin_left = 91.0 +margin_right = 249.0 +margin_bottom = 20.0 +text = "Interpolation Type" +items = [ "Nearest", null, false, 0, null, "Bilinear", null, false, 1, null, "Cubic", null, false, 2, null, "Trilinear", null, false, 3, null ] +selected = 0 + +[node name="AnimationTimer" type="Timer" parent="."] [connection signal="toggled" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftIndicatorCheckbox" to="." method="_on_LeftIndicatorCheckbox_toggled"] [connection signal="popup_closed" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftColorPickerButton" to="." method="_can_draw_true"] [connection signal="pressed" from="UI/ToolPanel/Tools/ToolOptions/LeftToolOptions/LeftColorPickerButton" to="." method="_can_draw_false"] @@ -449,19 +651,29 @@ text = "64" [connection signal="popup_closed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/RightColorPickerButton" to="." method="_can_draw_true"] [connection signal="pressed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/RightColorPickerButton" to="." method="_can_draw_false"] [connection signal="value_changed" from="UI/ToolPanel/Tools/ToolOptions/RightToolOptions/BrushSize/RightBrushSizeEdit" to="." method="_on_RightBrushSizeEdit_value_changed"] -[connection signal="mouse_entered" from="UI/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"] -[connection signal="mouse_exited" from="UI/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"] -[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/AddLayerButton" to="." method="_on_AddLayerButton_pressed"] -[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/RemoveLayerButton" to="." method="_on_RemoveLayerButton_pressed"] -[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MoveUpLayer" to="." method="_on_MoveUpLayer_pressed"] -[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MoveDownLayer" to="." method="_on_MoveDownLayer_pressed"] -[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/CloneLayer" to="." method="_on_CloneLayer_pressed"] -[connection signal="pressed" from="UI/LayerPanel/ScrollContainer/VBoxLayerContainer/HBoxContainer/MergeDownLayer" to="." method="_on_MergeLayer_pressed"] +[connection signal="mouse_entered" from="UI/CanvasAndTimeline/ViewportContainer" to="." method="_on_ViewportContainer_mouse_entered"] +[connection signal="mouse_exited" from="UI/CanvasAndTimeline/ViewportContainer" to="." method="_on_ViewportContainer_mouse_exited"] +[connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/LoopAnim" to="." method="_on_LoopAnim_toggled"] +[connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/PlayBackwards" to="." method="_on_PlayBackwards_toggled"] +[connection signal="toggled" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/PlayForward" to="." method="_on_PlayForward_toggled"] +[connection signal="value_changed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/ButtonContainer/AnimationButtons/FPSValue" to="." method="_on_FPSValue_value_changed"] +[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/AddFrame" to="." method="_on_AddFrame_pressed"] +[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/RemoveFrame" to="." method="_on_RemoveFrame_pressed"] +[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/MoveFrameLeft" to="." method="_on_MoveFrameLeft_pressed"] +[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/MoveFrameRight" to="." method="_on_MoveFrameRight_pressed"] +[connection signal="pressed" from="UI/CanvasAndTimeline/AnimationTimeline/TimelineContainer/CenterContainer/FrameButtons/CloneFrame" to="." method="_on_CloneFrame_pressed"] +[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/AddLayerButton" to="." method="_on_AddLayerButton_pressed"] +[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/RemoveLayerButton" to="." method="_on_RemoveLayerButton_pressed"] +[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/MoveUpLayer" to="." method="_on_MoveUpLayer_pressed"] +[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/MoveDownLayer" to="." method="_on_MoveDownLayer_pressed"] +[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/CloneLayer" to="." method="_on_CloneLayer_pressed"] +[connection signal="pressed" from="UI/LayerPanel/LayersAndMisc/ScrollContainer/VBoxLayerContainer/CenterContainer/LayerButtons/MergeDownLayer" to="." method="_on_MergeLayer_pressed"] [connection signal="confirmed" from="CreateNewImage" to="." method="_on_CreateNewImage_confirmed"] [connection signal="popup_hide" from="CreateNewImage" to="." method="_can_draw_true"] -[connection signal="file_selected" from="OpenSprite" to="." method="_on_OpenSprite_file_selected"] +[connection signal="files_selected" from="OpenSprite" to="." method="_on_OpenSprite_files_selected"] [connection signal="popup_hide" from="OpenSprite" to="." method="_on_OpenSprite_popup_hide"] [connection signal="file_selected" from="SaveSprite" to="." method="_on_SaveSprite_file_selected"] [connection signal="popup_hide" from="SaveSprite" to="." method="_can_draw_true"] [connection signal="confirmed" from="ScaleImage" to="." method="_on_ScaleImage_confirmed"] [connection signal="popup_hide" from="ScaleImage" to="." method="_can_draw_true"] +[connection signal="timeout" from="AnimationTimer" to="." method="_on_AnimationTimer_timeout"] diff --git a/Scripts/CameraMovement.gd b/Scripts/CameraMovement.gd index 99b1fb3d1..749be2788 100644 --- a/Scripts/CameraMovement.gd +++ b/Scripts/CameraMovement.gd @@ -1,7 +1,7 @@ extends Camera2D var zoom_min := Vector2(0.005, 0.005) -var zoom_max := Vector2(0.8, 0.8) +var zoom_max := Vector2.ONE var drag := false @@ -21,5 +21,11 @@ func _input(event) -> void: # Zoom Camera func zoom_camera(dir : int) -> void: var zoom_margin = zoom * dir / 10 - if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max: - zoom += zoom_margin \ No newline at end of file + #if zoom + zoom_margin > zoom_min && zoom + zoom_margin < zoom_max: + if zoom + zoom_margin > zoom_min: + zoom += zoom_margin + + if zoom > zoom_max: + zoom = zoom_max + + Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / zoom.x, 0.01)] \ No newline at end of file diff --git a/Scripts/Canvas.gd b/Scripts/Canvas.gd index 617f76f41..26256bdc8 100644 --- a/Scripts/Canvas.gd +++ b/Scripts/Canvas.gd @@ -4,20 +4,18 @@ class_name Canvas var layers := [] var current_layer_index := 0 var trans_background : ImageTexture -var current_sprite : Image var location := Vector2.ZERO var size := Vector2(64, 64) +var frame := 0 +var frame_button : VBoxContainer +var frame_texture_rect : TextureRect var previous_mouse_pos := Vector2.ZERO var mouse_inside_canvas := false #used for undo var sprite_changed_this_frame := false #for optimization purposes -var left_square_indicator_visible := true -var right_square_indicator_visible := false -var left_brush_size := 1 -var right_brush_size := 1 + var is_making_line := false var line_2d : Line2D -var draw_grid := false # Called when the node enters the scene tree for the first time. func _ready() -> void: @@ -27,24 +25,29 @@ func _ready() -> void: trans_background.create_from_image(load("res://Transparent Background.png"), 0) #The sprite itself - if !current_sprite: - current_sprite = Image.new() - current_sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8) + if layers.empty(): + var sprite := Image.new() + sprite.create(size.x, size.y, false, Image.FORMAT_RGBA8) - current_sprite.lock() - var tex := ImageTexture.new() - tex.create_from_image(current_sprite, 0) - - #Store [Image, ImageTexture, Layer Name, Visibity boolean] - layers.append([current_sprite, tex, "Layer 0", true]) + sprite.lock() + var tex := ImageTexture.new() + tex.create_from_image(sprite, 0) + + #Store [Image, ImageTexture, Layer Name, Visibity boolean] + layers.append([sprite, tex, "Layer 0", true]) generate_layer_panels() - #Set camera offset to the center of canvas - $"../Camera2D".offset = size / 2 - #Set camera zoom based on the sprite size - var bigger = max(size.x, size.y) - $"../Camera2D".zoom_max = Vector2(bigger, bigger) * 0.01 - $"../Camera2D".zoom = Vector2(bigger, bigger) * 0.002 + + frame_button = load("res://FrameButton.tscn").instance() + frame_button.name = "Frame_%s" % frame + frame_button.get_node("FrameButton").frame = frame + frame_button.get_node("FrameID").text = str(frame) + Global.frame_container.add_child(frame_button) + + frame_texture_rect = Global.find_node_by_name(frame_button, "FrameTexture") + frame_texture_rect.texture = layers[0][1] #ImageTexture current_layer_index + + camera_zoom() # warning-ignore:unused_argument func _process(delta) -> void: @@ -60,11 +63,16 @@ func _process(delta) -> void: current_mouse_button = "R" current_action = Global.current_right_tool + if visible: + if !point_in_rectangle(mouse_pos, location, location + size): + if !Input.is_mouse_button_pressed(BUTTON_LEFT) && !Input.is_mouse_button_pressed(BUTTON_RIGHT): + if mouse_inside_canvas: + mouse_inside_canvas = false + Global.cursor_position_label.text = "[%sx%s]" % [size.x, size.y] + else: + var mouse_pos_floored := mouse_pos.floor() + Global.cursor_position_label.text = "[%sx%s] %s, %s" % [size.x, size.y, mouse_pos_floored.x, mouse_pos_floored.y] - if !point_in_rectangle(mouse_pos, location, location + size): - if !Input.is_mouse_button_pressed(BUTTON_LEFT) && !Input.is_mouse_button_pressed(BUTTON_RIGHT): - if mouse_inside_canvas: - mouse_inside_canvas = false match current_action: "Pencil": var current_color : Color @@ -76,7 +84,7 @@ func _process(delta) -> void: "Eraser": pencil_and_eraser(mouse_pos, Color(0, 0, 0, 0), current_mouse_button) "Fill": - if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus: + if point_in_rectangle(mouse_pos, location, location + size) && Global.can_draw && Global.has_focus && Global.current_frame == frame: var current_color : Color if current_mouse_button == "L": current_color = Global.left_color_picker.color @@ -94,9 +102,18 @@ func _process(delta) -> void: if sprite_changed_this_frame: update_texture(current_layer_index) -func update_texture(layer_index : int): +func update_texture(layer_index : int) -> void: layers[layer_index][1].create_from_image(layers[layer_index][0], 0) get_layer_container(layer_index).get_child(0).get_child(1).texture = layers[layer_index][1] + + var whole_image := Image.new() + whole_image.create(size.x, size.y, false, Image.FORMAT_RGBA8) + for layer in layers: + whole_image.blend_rect(layer[0], Rect2(position, size), Vector2.ZERO) + layer[0].lock() + var whole_image_texture := ImageTexture.new() + whole_image_texture.create_from_image(whole_image, 0) + frame_texture_rect.texture = whole_image_texture func get_layer_container(layer_index : int) -> PanelContainer: for container in Global.vbox_layer_container.get_children(): @@ -112,7 +129,7 @@ func _draw() -> void: draw_texture(texture[1], location) #Idea taken from flurick (on GitHub) - if draw_grid: + if Global.draw_grid: for x in size.x: draw_line(Vector2(x, location.y), Vector2(x, size.y), Color.black, true) for y in size.y: @@ -122,14 +139,14 @@ func _draw() -> void: var mouse_pos := get_local_mouse_position() - location if point_in_rectangle(mouse_pos, location, location + size): mouse_pos = mouse_pos.floor() - if left_square_indicator_visible: - var start_pos_x = mouse_pos.x - (left_brush_size >> 1) - var start_pos_y = mouse_pos.y - (left_brush_size >> 1) - draw_rect(Rect2(start_pos_x, start_pos_y, left_brush_size, left_brush_size), Color.blue, false) - if right_square_indicator_visible: - var start_pos_x = mouse_pos.x - (right_brush_size >> 1) - var start_pos_y = mouse_pos.y - (right_brush_size >> 1) - draw_rect(Rect2(start_pos_x, start_pos_y, right_brush_size, right_brush_size), Color.red, false) + if Global.left_square_indicator_visible: + var start_pos_x = mouse_pos.x - (Global.left_brush_size >> 1) + var start_pos_y = mouse_pos.y - (Global.left_brush_size >> 1) + draw_rect(Rect2(start_pos_x, start_pos_y, Global.left_brush_size, Global.left_brush_size), Color.blue, false) + if Global.right_square_indicator_visible: + var start_pos_x = mouse_pos.x - (Global.right_brush_size >> 1) + var start_pos_y = mouse_pos.y - (Global.right_brush_size >> 1) + draw_rect(Rect2(start_pos_x, start_pos_y, Global.right_brush_size, Global.right_brush_size), Color.red, false) func generate_layer_panels() -> void: for child in Global.vbox_layer_container.get_children(): @@ -155,6 +172,19 @@ func generate_layer_panels() -> void: layer_container.get_child(0).get_child(1).texture = layers[i][1] Global.vbox_layer_container.add_child(layer_container) +func camera_zoom() -> void: + #Set camera offset to the center of canvas + Global.camera.offset = size / 2 + #Set camera zoom based on the sprite size + var bigger = max(size.x, size.y) + var zoom_max := Vector2(bigger, bigger) * 0.01 + if zoom_max > Vector2.ONE: + Global.camera.zoom_max = zoom_max + else: + Global.camera.zoom_max = Vector2.ONE + Global.camera.zoom = Vector2(bigger, bigger) * 0.002 + Global.zoom_level_label.text = "Zoom: x%s" % [stepify(1 / $"../Camera2D".zoom.x, 0.01)] + func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button : String) -> void: if Input.is_key_pressed(KEY_SHIFT): if !is_making_line: @@ -168,9 +198,9 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button else: var brush_size := 1 if current_mouse_button == "L": - brush_size = left_brush_size + brush_size = Global.left_brush_size elif current_mouse_button == "R": - brush_size = right_brush_size + brush_size = Global.right_brush_size if is_making_line: fill_gaps(mouse_pos, color, brush_size) @@ -187,7 +217,7 @@ func pencil_and_eraser(mouse_pos : Vector2, color : Color, current_mouse_button fill_gaps(mouse_pos, color, brush_size) func draw_pixel(pos : Vector2, color : Color, brush_size : int) -> void: - if Global.can_draw && Global.has_focus: + if Global.can_draw && Global.has_focus && Global.current_frame == frame: var start_pos_x = pos.x - (brush_size >> 1) var start_pos_y = pos.y - (brush_size >> 1) for cur_pos_x in range(start_pos_x, start_pos_x + brush_size): diff --git a/Scripts/FrameButton.gd b/Scripts/FrameButton.gd new file mode 100644 index 000000000..3802568a1 --- /dev/null +++ b/Scripts/FrameButton.gd @@ -0,0 +1,8 @@ +extends Button + +var frame := 0 + +func _on_FrameButton_pressed() -> void: + Global.current_frame = frame + #print(len(Global.canvases)) + Global.change_frame() \ No newline at end of file diff --git a/Scripts/Global.gd b/Scripts/Global.gd index 7a068a146..e1223af8e 100644 --- a/Scripts/Global.gd +++ b/Scripts/Global.gd @@ -1,22 +1,44 @@ extends Node +# warning-ignore:unused_class_variable +var current_frame := 0 # warning-ignore:unused_class_variable var can_draw := false # warning-ignore:unused_class_variable var has_focus := true +# warning-ignore:unused_class_variable +var draw_grid := false +var canvases := [] var canvas : Canvas -var canvas_parent +var canvas_parent : Node +# warning-ignore:unused_class_variable +var left_square_indicator_visible := true +# warning-ignore:unused_class_variable +var right_square_indicator_visible := false +# warning-ignore:unused_class_variable +var left_brush_size := 1 +# warning-ignore:unused_class_variable +var right_brush_size := 1 +var camera : Camera2D var left_color_picker : ColorPickerButton var right_color_picker : ColorPickerButton var file_menu : MenuButton var edit_menu : MenuButton var left_indicator : Sprite var right_indicator : Sprite +var play_forward : Button +var play_backwards : Button +var frame_container : HBoxContainer +var remove_frame_button : Button +var move_left_frame_button : Button +var move_right_frame_button : Button var vbox_layer_container : VBoxContainer var remove_layer_button : Button var move_up_layer_button : Button var move_down_layer_button : Button var merge_down_layer_button : Button +var cursor_position_label : Label +var zoom_level_label : Label # warning-ignore:unused_class_variable var current_left_tool := "Pencil" # warning-ignore:unused_class_variable @@ -25,18 +47,28 @@ var current_right_tool := "Eraser" func _ready() -> void: var root = get_tree().get_root() canvas = find_node_by_name(root, "Canvas") + canvases.append(canvas) canvas_parent = canvas.get_parent() + camera = find_node_by_name(canvas_parent, "Camera2D") left_color_picker = find_node_by_name(root, "LeftColorPickerButton") right_color_picker = find_node_by_name(root, "RightColorPickerButton") file_menu = find_node_by_name(root, "FileMenu") edit_menu = find_node_by_name(root, "EditMenu") left_indicator = find_node_by_name(root, "LeftIndicator") right_indicator = find_node_by_name(root, "RightIndicator") + play_forward = find_node_by_name(root, "PlayForward") + play_backwards = find_node_by_name(root, "PlayBackwards") + frame_container = find_node_by_name(root, "FrameContainer") + remove_frame_button = find_node_by_name(root, "RemoveFrame") + move_left_frame_button = find_node_by_name(root, "MoveFrameLeft") + move_right_frame_button = find_node_by_name(root, "MoveFrameRight") vbox_layer_container = find_node_by_name(root, "VBoxLayerContainer") remove_layer_button = find_node_by_name(root, "RemoveLayerButton") move_up_layer_button = find_node_by_name(root, "MoveUpLayer") move_down_layer_button = find_node_by_name(root, "MoveDownLayer") merge_down_layer_button = find_node_by_name(root, "MergeDownLayer") + cursor_position_label = find_node_by_name(root, "CursorPosition") + zoom_level_label = find_node_by_name(root, "ZoomLevel") #Thanks to https://godotengine.org/qa/17524/how-to-find-an-instanced-scene-by-its-name func find_node_by_name(root, node_name) -> Node: @@ -48,4 +80,27 @@ func find_node_by_name(root, node_name) -> Node: var found = find_node_by_name(child, node_name) if found: return found - return null \ No newline at end of file + return null + +func change_frame() -> void: + for c in canvases: + c.visible = false + canvas = canvases[current_frame] + canvas.visible = true + canvas.generate_layer_panels() + handle_layer_order_buttons() + +func handle_layer_order_buttons() -> void: + if current_frame == 0: + move_left_frame_button.disabled = true + move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN + else: + move_left_frame_button.disabled = false + move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + + if current_frame == canvases.size() - 1: + move_right_frame_button.disabled = true + move_right_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN + else: + move_right_frame_button.disabled = false + move_right_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND \ No newline at end of file diff --git a/Scripts/Main.gd b/Scripts/Main.gd index ab2f0cf3b..c49392e25 100644 --- a/Scripts/Main.gd +++ b/Scripts/Main.gd @@ -5,21 +5,30 @@ var opensprite_file_selected := false var pencil_tool var eraser_tool var fill_tool +var export_all_frames : CheckButton +var export_as_single_file : CheckButton +var export_vertical_spritesheet : CheckButton +var fps := 1.0 +var animation_loop := false +var animation_forward := true # Called when the node enters the scene tree for the first time. func _ready() -> void: var file_menu_items := { "New..." : KEY_MASK_CTRL + KEY_N, + #The import and export key shortcuts will change, + #and they will be bound to Open and Save/Save as once I + #make a custom file for Pixelorama projects "Import..." : KEY_MASK_CTRL + KEY_O, "Export..." : KEY_MASK_CTRL + KEY_S, "Export as..." : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_S, "Quit" : KEY_MASK_CTRL + KEY_Q } var edit_menu_items := { + "Scale Image" : 0, "Show Grid" : KEY_MASK_CTRL + KEY_G #"Undo" : KEY_MASK_CTRL + KEY_Z, #"Redo" : KEY_MASK_SHIFT + KEY_MASK_CTRL + KEY_Z, - #"Scale Image" : 0 } var file_menu : PopupMenu = Global.file_menu.get_popup() var edit_menu : PopupMenu = Global.edit_menu.get_popup() @@ -42,6 +51,16 @@ func _ready() -> void: eraser_tool.connect("pressed", self, "_on_Tool_pressed", [eraser_tool]) fill_tool.connect("pressed", self, "_on_Tool_pressed", [fill_tool]) + export_all_frames = CheckButton.new() + export_all_frames.text = "Export all frames?" + export_as_single_file = CheckButton.new() + export_as_single_file.text = "Export frames as a single file?" + export_vertical_spritesheet = CheckButton.new() + export_vertical_spritesheet.text = "Vertical spritesheet?" + $SaveSprite.get_vbox().add_child(export_all_frames) + $SaveSprite.get_vbox().add_child(export_as_single_file) + $SaveSprite.get_vbox().add_child(export_vertical_spritesheet) + func _input(event): #Handle tool shortcuts if event.is_action_pressed("right_pencil_tool"): @@ -57,6 +76,7 @@ func _input(event): elif event.is_action_pressed("left_fill_tool"): _on_Tool_pressed(fill_tool, false, true) + func file_menu_id_pressed(id : int) -> void: match id: 0: #New @@ -71,7 +91,7 @@ func file_menu_id_pressed(id : int) -> void: $SaveSprite.popup_centered() Global.can_draw = false else: - save_sprite() + export_project() 3: #Export as $SaveSprite.popup_centered() Global.can_draw = false @@ -80,58 +100,165 @@ func file_menu_id_pressed(id : int) -> void: func edit_menu_id_pressed(id : int) -> void: match id: - 0: #Show grid - Global.canvas.draw_grid = !Global.canvas.draw_grid + 0: #Scale Image + $ScaleImage.popup_centered() + Global.can_draw = false + 1: #Show grid + Global.draw_grid = !Global.draw_grid func _on_CreateNewImage_confirmed() -> void: - var width = float($CreateNewImage/VBoxContainer/WidthCont/LineEdit.text) - var height = float($CreateNewImage/VBoxContainer/HeightCont/LineEdit.text) - width = clamp(width, 1, 16384) - height = clamp(height, 1, 16384) + var width = float($CreateNewImage/VBoxContainer/WidthCont/WidthValue.value) + var height = float($CreateNewImage/VBoxContainer/HeightCont/HeightValue.value) new_canvas(Vector2(width, height).floor()) -func _on_OpenSprite_file_selected(path : String) -> void: - var image = Image.new() - var err = image.load(path) - if err == OK: - opensprite_file_selected = true - new_canvas(image.get_size(), image) - else: - OS.alert("Can't load file") +#func _on_OpenSprite_file_selected(path : String) -> void: +# var image = Image.new() +# var err = image.load(path) +# if err == OK: +# opensprite_file_selected = true +# new_canvas(image.get_size(), image) +# else: +# OS.alert("Can't load file") -func new_canvas(size : Vector2, sprite : Image = null) -> void: - var left_indicator_visible = Global.canvas.left_square_indicator_visible - var right_indicator_visible = Global.canvas.right_square_indicator_visible - var left_brush_size = Global.canvas.left_brush_size - var right_brush_size = Global.canvas.right_brush_size - +func _on_OpenSprite_files_selected(paths) -> void: for child in Global.vbox_layer_container.get_children(): if child is PanelContainer: child.queue_free() - Global.canvas.queue_free() + for child in Global.frame_container.get_children(): + child.queue_free() + for child in Global.canvas_parent.get_children(): + if child is Canvas: + child.queue_free() + Global.canvases.clear() + + #Find the biggest image and let it handle the camera zoom options + var max_size : Vector2 + var biggest_canvas : Canvas + var i := 0 + for path in paths: + var image = Image.new() + var err = image.load(path) + if err == OK: + opensprite_file_selected = true + var canvas : Canvas = load("res://Canvas.tscn").instance() + canvas.size = image.get_size() + image.convert(Image.FORMAT_RGBA8) + image.lock() + var tex := ImageTexture.new() + tex.create_from_image(image, 0) + #Store [Image, ImageTexture, Layer Name, Visibity boolean] + canvas.layers.append([image, tex, "Layer 0", true]) + canvas.frame = i + Global.canvas_parent.add_child(canvas) + Global.canvases.append(canvas) + canvas.visible = false + if i == 0: + max_size = canvas.size + biggest_canvas = canvas + else: + if canvas.size > max_size: + biggest_canvas = canvas + + else: + OS.alert("Can't load file") + + i += 1 + Global.current_frame = i - 1 + Global.canvas = Global.canvases[Global.canvases.size() - 1] + Global.canvas.visible = true + Global.handle_layer_order_buttons() + biggest_canvas.camera_zoom() + if i > 1: + Global.remove_frame_button.disabled = false + Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + else: + Global.remove_frame_button.disabled = true + Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN + +func new_canvas(size : Vector2, sprite : Image = null) -> void: + for child in Global.vbox_layer_container.get_children(): + if child is PanelContainer: + child.queue_free() + for child in Global.frame_container.get_children(): + child.queue_free() + for child in Global.canvas_parent.get_children(): + if child is Canvas: + child.queue_free() + Global.canvases.clear() Global.canvas = load("res://Canvas.tscn").instance() Global.canvas.size = size - Global.canvas.left_square_indicator_visible = left_indicator_visible - Global.canvas.right_square_indicator_visible = right_indicator_visible - Global.canvas.left_brush_size = left_brush_size - Global.canvas.right_brush_size = right_brush_size - if sprite: - Global.canvas.current_sprite = sprite - Global.canvas.current_sprite.convert(Image.FORMAT_RGBA8) +# if sprite: +# var layer0 := sprite +# layer0.convert(Image.FORMAT_RGBA8) +# var tex := ImageTexture.new() +# tex.create_from_image(layer0, 0) +# #Store [Image, ImageTexture, Layer Name, Visibity boolean] +# Global.canvas.layers.append([layer0, tex, "Layer 0", true]) Global.canvas_parent.add_child(Global.canvas) + Global.canvases.append(Global.canvas) + Global.current_frame = 0 + Global.remove_frame_button.disabled = true + Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN func _on_SaveSprite_file_selected(path : String) -> void: current_path = path - save_sprite() + export_project() -func save_sprite() -> void: +func export_project() -> void: + if export_all_frames.pressed: + if !export_as_single_file.pressed: + var i := 0 + for canvas in Global.canvases: + var path := "%s_%s" % [current_path, str(i)] + path = path.replace(".png", "") + path = "%s.png" % path + save_sprite(canvas, path) + i += 1 + else: + save_spritesheet() + else: + save_sprite(Global.canvas, current_path) + +func save_sprite(canvas : Canvas, path : String) -> void: var whole_image := Image.new() - whole_image.create(Global.canvas.size.x, Global.canvas.size.y, false, Image.FORMAT_RGBA8) - for layer in Global.canvas.layers: - whole_image.blend_rect(layer[0], Rect2(Global.canvas.position, Global.canvas.size), Vector2.ZERO) + whole_image.create(canvas.size.x, canvas.size.y, false, Image.FORMAT_RGBA8) + for layer in canvas.layers: + whole_image.blend_rect(layer[0], Rect2(canvas.position, canvas.size), Vector2.ZERO) layer[0].lock() - #var err = Global.canvas.current_sprite.save_png(current_path) + var err = whole_image.save_png(path) + if err != OK: + OS.alert("Can't save file") + +func save_spritesheet() -> void: + var width + var height + if export_vertical_spritesheet.pressed: + width = Global.canvas.size.x + height = 0 + for canvas in Global.canvases: + height += canvas.size.y + if canvas.size.x > width: + width = canvas.size.x + else: + width = 0 + height = Global.canvas.size.y + for canvas in Global.canvases: + width += canvas.size.x + if canvas.size.y > height: + height = canvas.size.y + var whole_image := Image.new() + whole_image.create(width, height, false, Image.FORMAT_RGBA8) + var dst := Vector2.ZERO + for canvas in Global.canvases: + for layer in canvas.layers: + whole_image.blend_rect(layer[0], Rect2(canvas.position, canvas.size), dst) + layer[0].lock() + if export_vertical_spritesheet.pressed: + dst += Vector2(0, canvas.size.y) + else: + dst += Vector2(canvas.size.x, 0) + var err = whole_image.save_png(current_path) if err != OK: OS.alert("Can't save file") @@ -163,22 +290,19 @@ func _on_Tool_pressed(tool_pressed : BaseButton, mouse_press := true, key_for_le Global.right_indicator.get_parent().remove_child(Global.right_indicator) tool_pressed.add_child(Global.right_indicator) - func _on_ScaleImage_confirmed() -> void: - var width = float($ScaleImage/VBoxContainer/WidthCont/LineEdit.text) - var height = float($ScaleImage/VBoxContainer/HeightCont/LineEdit.text) - width = clamp(width, 1, 16384) - height = clamp(height, 1, 16384) - #var sprites := [] + var width = float($ScaleImage/VBoxContainer/WidthCont/WidthValue.value) + var height = float($ScaleImage/VBoxContainer/HeightCont/HeightValue.value) for i in range(Global.canvas.layers.size() - 1, -1, -1): var sprite = Image.new() sprite = Global.canvas.layers[i][1].get_data() - sprite.resize(width, height) + sprite.resize(width, height, $ScaleImage/VBoxContainer/InterpolationContainer/InterpolationType.selected) Global.canvas.layers[i][0] = sprite Global.canvas.layers[i][0].lock() Global.canvas.update_texture(i) - + Global.canvas.size = Vector2(width, height).floor() + Global.canvas.camera_zoom() func add_layer(is_new := true) -> void: var new_layer := Image.new() @@ -226,16 +350,164 @@ func _on_MergeLayer_pressed() -> void: Global.canvas.update_texture(Global.canvas.current_layer_index - 1) _on_RemoveLayerButton_pressed() -func _on_LeftIndicatorCheckbox_toggled(button_pressed): - Global.canvas.left_square_indicator_visible = button_pressed +func _on_LeftIndicatorCheckbox_toggled(button_pressed) -> void: + Global.left_square_indicator_visible = button_pressed -func _on_RightIndicatorCheckbox_toggled(button_pressed): - Global.canvas.right_square_indicator_visible = button_pressed +func _on_RightIndicatorCheckbox_toggled(button_pressed) -> void: + Global.right_square_indicator_visible = button_pressed -func _on_LeftBrushSizeEdit_value_changed(value): +func _on_LeftBrushSizeEdit_value_changed(value) -> void: var new_size = int(value) - Global.canvas.left_brush_size = new_size + Global.left_brush_size = new_size -func _on_RightBrushSizeEdit_value_changed(value): +func _on_RightBrushSizeEdit_value_changed(value) -> void: var new_size = int(value) - Global.canvas.right_brush_size = new_size + Global.right_brush_size = new_size + +func _on_AddFrame_pressed() -> void: + var canvas = load("res://Canvas.tscn").instance() + canvas.size = Global.canvas.size + Global.current_frame = Global.canvases.size() + canvas.frame = Global.current_frame + for canvas in Global.canvases: + canvas.visible = false + Global.canvases.append(canvas) + Global.canvas = canvas + + Global.canvas_parent.add_child(canvas) + Global.remove_frame_button.disabled = false + Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + Global.move_left_frame_button.disabled = false + Global.move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + +func _on_RemoveFrame_pressed() -> void: + Global.canvas.frame_button.queue_free() + Global.canvas.queue_free() + Global.canvases.remove(Global.current_frame) + for canvas in Global.canvases: + if canvas.frame > Global.current_frame: + canvas.frame -= 1 + canvas.frame_button.get_node("FrameButton").frame = canvas.frame + canvas.frame_button.get_node("FrameID").text = str(canvas.frame) + if Global.current_frame > 0: + Global.current_frame -= 1 + if len(Global.canvases) == 1: + Global.remove_frame_button.disabled = true + Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN + Global.canvas = Global.canvases[Global.current_frame] + Global.canvas.visible = true + Global.canvas.generate_layer_panels() + Global.handle_layer_order_buttons() + + +func _on_CloneFrame_pressed() -> void: + var canvas = load("res://Canvas.tscn").instance() + canvas.size = Global.canvas.size + #canvas.layers = Global.canvas.layers.duplicate(true) + for layer in Global.canvas.layers: + var sprite := Image.new() + sprite.copy_from(layer[0]) + sprite.lock() + var tex := ImageTexture.new() + tex.create_from_image(sprite, 0) + canvas.layers.append([sprite, tex, layer[2], layer[3]]) + Global.current_frame = Global.canvases.size() + canvas.frame = Global.current_frame + for canvas in Global.canvases: + canvas.visible = false + Global.canvases.append(canvas) + Global.canvas = canvas + + Global.canvas_parent.add_child(canvas) + Global.remove_frame_button.disabled = false + Global.remove_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + Global.move_left_frame_button.disabled = false + Global.move_left_frame_button.mouse_default_cursor_shape = Control.CURSOR_POINTING_HAND + +func _on_MoveFrameLeft_pressed() -> void: + change_frame_order(-1) + +func _on_MoveFrameRight_pressed() -> void: + change_frame_order(1) + +func change_frame_order(rate : int) -> void: + var frame_button = Global.frame_container.get_node("Frame_%s" % Global.current_frame) + var change = Global.current_frame + rate + + var temp = Global.canvases[Global.current_frame] + Global.canvases[Global.current_frame] = Global.canvases[change] + Global.canvases[change] = temp + + #Clear frame button names first, to avoid duplicates like two Frame_0s + for canvas in Global.canvases: + canvas.frame_button.name = "frame" + + for canvas in Global.canvases: + canvas.frame = Global.canvases.find(canvas) + canvas.frame_button.name = "Frame_%s" % canvas.frame + canvas.frame_button.get_node("FrameButton").frame = canvas.frame + canvas.frame_button.get_node("FrameID").text = str(canvas.frame) + + Global.current_frame = change + Global.frame_container.move_child(frame_button, Global.current_frame) + Global.canvas_parent.move_child(Global.canvas, Global.current_frame) + #Global.canvas.generate_layer_panels() + Global.handle_layer_order_buttons() + + +func _on_PlayForward_toggled(button_pressed) -> void: + Global.play_backwards.pressed = false + Global.play_backwards.text = "Play Backwards" + + if button_pressed: + Global.play_forward.text = "Stop" + $AnimationTimer.wait_time = 1 / fps + $AnimationTimer.start() + animation_forward = true + else: + Global.play_forward.text = "Play Forward" + $AnimationTimer.stop() + +func _on_PlayBackwards_toggled(button_pressed) -> void: + Global.play_forward.pressed = false + Global.play_forward.text = "Play Forward" + + if button_pressed: + Global.play_backwards.text = "Stop" + $AnimationTimer.wait_time = 1 / fps + $AnimationTimer.start() + animation_forward = false + else: + Global.play_backwards.text = "Play Backwards" + $AnimationTimer.stop() + +func _on_AnimationTimer_timeout() -> void: + if animation_forward: + if Global.current_frame < Global.canvases.size() - 1: + Global.current_frame += 1 + else: + if animation_loop: + Global.current_frame = 0 + else: + Global.play_forward.pressed = false + Global.play_forward.text = "Play Forward" + $AnimationTimer.stop() + else: + if Global.current_frame > 0: + Global.current_frame -= 1 + else: + if animation_loop: + Global.current_frame = Global.canvases.size() - 1 + else: + Global.play_backwards.pressed = false + Global.play_backwards.text = "Play Backwards" + $AnimationTimer.stop() + + Global.change_frame() + +func _on_FPSValue_value_changed(value) -> void: + fps = float(value) + $AnimationTimer.wait_time = 1 / fps + +func _on_LoopAnim_toggled(button_pressed) -> void: + animation_loop = button_pressed \ No newline at end of file diff --git a/export_presets.cfg b/export_presets.cfg index 2cd5d2174..355a00f7a 100644 --- a/export_presets.cfg +++ b/export_presets.cfg @@ -23,8 +23,8 @@ binary_format/64_bits=true custom_template/release="" custom_template/debug="" application/icon="" -application/file_version="0.1" -application/product_version="0.1" +application/file_version="0.2" +application/product_version="0.2" application/company_name="Orama Interactive" application/product_name="Pixelorama" application/file_description=""