diff --git a/.import/.gdignore b/.import/.gdignore new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/.import/.gdignore @@ -0,0 +1 @@ + diff --git a/.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.md5 b/.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.md5 new file mode 100644 index 0000000..6a77ad3 --- /dev/null +++ b/.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.md5 @@ -0,0 +1,3 @@ +source_md5="fbb430a6091e78ab2a9a548004035642" +dest_md5="48be10b6d52b151385fc2fdc87e395dd" + diff --git a/.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.stex b/.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.stex new file mode 100644 index 0000000..aebcec5 Binary files /dev/null and b/.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.stex differ diff --git a/.import/DrumsOfTumbalku_Seq001_Sht020_Prt50_Ver01.png-6bd509f7b1257ad339e135fcf0f82063.md5 b/.import/DrumsOfTumbalku_Seq001_Sht020_Prt50_Ver01.png-6bd509f7b1257ad339e135fcf0f82063.md5 new file mode 100644 index 0000000..fdebf53 --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht020_Prt50_Ver01.png-6bd509f7b1257ad339e135fcf0f82063.md5 @@ -0,0 +1,3 @@ +source_md5="b5a8be1f678498b01abf663e12b85a2b" +dest_md5="4d7c45c21432358d393352193bd16fee" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht020_Prt51_Ver01.png-ed8e7382d3e58d0f39ad6fa8f86bc187.md5 b/.import/DrumsOfTumbalku_Seq001_Sht020_Prt51_Ver01.png-ed8e7382d3e58d0f39ad6fa8f86bc187.md5 new file mode 100644 index 0000000..ac91732 --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht020_Prt51_Ver01.png-ed8e7382d3e58d0f39ad6fa8f86bc187.md5 @@ -0,0 +1,3 @@ +source_md5="30cc001e8d67537e291b9c429cb3f4c7" +dest_md5="d403a8904844c45f068cd2ee7dcd2328" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht020_Prt52_Ver01.png-1f7fdfd39e4822aa2b869260dd311cb8.md5 b/.import/DrumsOfTumbalku_Seq001_Sht020_Prt52_Ver01.png-1f7fdfd39e4822aa2b869260dd311cb8.md5 new file mode 100644 index 0000000..574ae0a --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht020_Prt52_Ver01.png-1f7fdfd39e4822aa2b869260dd311cb8.md5 @@ -0,0 +1,3 @@ +source_md5="33d3c73368b9bba53b231b8e1f46c833" +dest_md5="97fcd59a56c0ca8281a0f2b8b10868a0" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht021_Prt01_Ver01.png-c661187cbb8325985f51986e3ec59693.md5 b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt01_Ver01.png-c661187cbb8325985f51986e3ec59693.md5 new file mode 100644 index 0000000..5b7515d --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt01_Ver01.png-c661187cbb8325985f51986e3ec59693.md5 @@ -0,0 +1,3 @@ +source_md5="6dd753a8cb4fe21eef9cb335fdfa2b30" +dest_md5="c7205c50fe77a67818dc9a7a93b0a52f" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht021_Prt02_Ver01.png-cd730e2bee943299e3f925aee7382dcf.md5 b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt02_Ver01.png-cd730e2bee943299e3f925aee7382dcf.md5 new file mode 100644 index 0000000..42bec58 --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt02_Ver01.png-cd730e2bee943299e3f925aee7382dcf.md5 @@ -0,0 +1,3 @@ +source_md5="02a58d1e7b111061b50dbcd673c05da2" +dest_md5="e56dee18b34294f05d82d88f68a50da2" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht021_Prt03_Ver01.png-c8200b98d67326d1ac69ba0b562c1357.md5 b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt03_Ver01.png-c8200b98d67326d1ac69ba0b562c1357.md5 new file mode 100644 index 0000000..9888717 --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt03_Ver01.png-c8200b98d67326d1ac69ba0b562c1357.md5 @@ -0,0 +1,3 @@ +source_md5="48f87d31fc37254b131907e4b5ada442" +dest_md5="15c72cceec020c9f9f20928936772d9f" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht021_Prt04_Ver01.png-a25020dfa0d282c8536d7c2ff1d4af17.md5 b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt04_Ver01.png-a25020dfa0d282c8536d7c2ff1d4af17.md5 new file mode 100644 index 0000000..f529715 --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht021_Prt04_Ver01.png-a25020dfa0d282c8536d7c2ff1d4af17.md5 @@ -0,0 +1,3 @@ +source_md5="07275d3541a19bdad6baab0a3c9ce922" +dest_md5="b4d63dc20b51aba68a1bccdd6534a0f0" + diff --git a/.import/DrumsOfTumbalku_Seq001_Sht022_Prt01_Ver01.png-e7fb974b5a0c206b9557aa014d990670.md5 b/.import/DrumsOfTumbalku_Seq001_Sht022_Prt01_Ver01.png-e7fb974b5a0c206b9557aa014d990670.md5 new file mode 100644 index 0000000..1c1a6b8 --- /dev/null +++ b/.import/DrumsOfTumbalku_Seq001_Sht022_Prt01_Ver01.png-e7fb974b5a0c206b9557aa014d990670.md5 @@ -0,0 +1,3 @@ +source_md5="857c30011fde464d3597c448ff1c7859" +dest_md5="8f4f3d30af42d8f0709831e5c6b72824" + diff --git a/.import/EditAddRemove.svg-c43218f5db81736f41d7c4408b4f578c.md5 b/.import/EditAddRemove.svg-c43218f5db81736f41d7c4408b4f578c.md5 new file mode 100644 index 0000000..1f7cd63 --- /dev/null +++ b/.import/EditAddRemove.svg-c43218f5db81736f41d7c4408b4f578c.md5 @@ -0,0 +1,3 @@ +source_md5="d04257d408a91092b339775325bd0b85" +dest_md5="3e515abbf780b102cc79e7876c125e9b" + diff --git a/.import/EditAddRemove.svg-df40479069b92165e9de7c8e2e477f7e.md5 b/.import/EditAddRemove.svg-df40479069b92165e9de7c8e2e477f7e.md5 new file mode 100644 index 0000000..1f7cd63 --- /dev/null +++ b/.import/EditAddRemove.svg-df40479069b92165e9de7c8e2e477f7e.md5 @@ -0,0 +1,3 @@ +source_md5="d04257d408a91092b339775325bd0b85" +dest_md5="3e515abbf780b102cc79e7876c125e9b" + diff --git a/.import/EditAddRemove.svg-df40479069b92165e9de7c8e2e477f7e.stex b/.import/EditAddRemove.svg-df40479069b92165e9de7c8e2e477f7e.stex new file mode 100644 index 0000000..ac23161 Binary files /dev/null and b/.import/EditAddRemove.svg-df40479069b92165e9de7c8e2e477f7e.stex differ diff --git a/.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.md5 b/.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.md5 new file mode 100644 index 0000000..63bae00 --- /dev/null +++ b/.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.md5 @@ -0,0 +1,3 @@ +source_md5="d7220d9630640ff25761269afe45b1f0" +dest_md5="16af9fadaa12573cbab460101f060adc" + diff --git a/.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.stex b/.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.stex new file mode 100644 index 0000000..bfc5af4 Binary files /dev/null and b/.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.stex differ diff --git a/.import/Evade.wav-b2abb2405565f7ca3739653dedcbd2ce.md5 b/.import/Evade.wav-b2abb2405565f7ca3739653dedcbd2ce.md5 new file mode 100644 index 0000000..9d0590a --- /dev/null +++ b/.import/Evade.wav-b2abb2405565f7ca3739653dedcbd2ce.md5 @@ -0,0 +1,3 @@ +source_md5="20bddc2277df7a5e232108fe2cf259a3" +dest_md5="835e32950883248faefab96c5b8588bc" + diff --git a/.import/GridLayout.svg-23d92859af26c07aec5cf14d0c12dd34.md5 b/.import/GridLayout.svg-23d92859af26c07aec5cf14d0c12dd34.md5 new file mode 100644 index 0000000..3c47feb --- /dev/null +++ b/.import/GridLayout.svg-23d92859af26c07aec5cf14d0c12dd34.md5 @@ -0,0 +1,3 @@ +source_md5="52a46925fa1f144aeae31a3a11c7f353" +dest_md5="dc76563bee5be941761508b795ff7ee4" + diff --git a/.import/GuiGraphNodePort.svg-8e5cb865060deb003360ef2a70fde05f.md5 b/.import/GuiGraphNodePort.svg-8e5cb865060deb003360ef2a70fde05f.md5 new file mode 100644 index 0000000..e3a3702 --- /dev/null +++ b/.import/GuiGraphNodePort.svg-8e5cb865060deb003360ef2a70fde05f.md5 @@ -0,0 +1,3 @@ +source_md5="c3c11c1f2b801457223e2aa398ef5d7e" +dest_md5="a841854c1e079bd7c86e2eacbb4e348d" + diff --git a/.import/GuiGraphNodePort.svg-f996f360724d56faf3d0b9ea20fa4c54.md5 b/.import/GuiGraphNodePort.svg-f996f360724d56faf3d0b9ea20fa4c54.md5 new file mode 100644 index 0000000..e3a3702 --- /dev/null +++ b/.import/GuiGraphNodePort.svg-f996f360724d56faf3d0b9ea20fa4c54.md5 @@ -0,0 +1,3 @@ +source_md5="c3c11c1f2b801457223e2aa398ef5d7e" +dest_md5="a841854c1e079bd7c86e2eacbb4e348d" + diff --git a/.import/GuiGraphNodePort.svg-f996f360724d56faf3d0b9ea20fa4c54.stex b/.import/GuiGraphNodePort.svg-f996f360724d56faf3d0b9ea20fa4c54.stex new file mode 100644 index 0000000..bc4affb Binary files /dev/null and b/.import/GuiGraphNodePort.svg-f996f360724d56faf3d0b9ea20fa4c54.stex differ diff --git a/.import/Image.svg-16a71af4b0d0217a7900878a871dc450.md5 b/.import/Image.svg-16a71af4b0d0217a7900878a871dc450.md5 new file mode 100644 index 0000000..5cf780a --- /dev/null +++ b/.import/Image.svg-16a71af4b0d0217a7900878a871dc450.md5 @@ -0,0 +1,3 @@ +source_md5="260da0f52c0f2bace9d6cd04432bf53b" +dest_md5="78fad60d23226b2a35259943e507d149" + diff --git a/.import/Image.svg-16a71af4b0d0217a7900878a871dc450.stex b/.import/Image.svg-16a71af4b0d0217a7900878a871dc450.stex new file mode 100644 index 0000000..e44c634 Binary files /dev/null and b/.import/Image.svg-16a71af4b0d0217a7900878a871dc450.stex differ diff --git a/.import/Image.svg-7c0b2485257dcbaa8414cb4c6ffacaff.md5 b/.import/Image.svg-7c0b2485257dcbaa8414cb4c6ffacaff.md5 new file mode 100644 index 0000000..5cf780a --- /dev/null +++ b/.import/Image.svg-7c0b2485257dcbaa8414cb4c6ffacaff.md5 @@ -0,0 +1,3 @@ +source_md5="260da0f52c0f2bace9d6cd04432bf53b" +dest_md5="78fad60d23226b2a35259943e507d149" + diff --git a/.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.md5 b/.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.md5 new file mode 100644 index 0000000..0ebd0db --- /dev/null +++ b/.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.md5 @@ -0,0 +1,3 @@ +source_md5="6f5793da9defb56542cba57debf6f89e" +dest_md5="da73b7410047ea2b27d960c81898378d" + diff --git a/.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.stex b/.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.stex new file mode 100644 index 0000000..d4be844 Binary files /dev/null and b/.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.stex differ diff --git a/.import/Jump.wav-c379d1627ff027da7972f8ad3083e9f0.md5 b/.import/Jump.wav-c379d1627ff027da7972f8ad3083e9f0.md5 new file mode 100644 index 0000000..0949178 --- /dev/null +++ b/.import/Jump.wav-c379d1627ff027da7972f8ad3083e9f0.md5 @@ -0,0 +1,3 @@ +source_md5="57fd850b8ab31a453b12ce597b34b02d" +dest_md5="c25690379ef0d63a6856ec762ae68fd0" + diff --git a/.import/Load.svg-b891ac6d40504b3c1e708e068830a830.md5 b/.import/Load.svg-b891ac6d40504b3c1e708e068830a830.md5 new file mode 100644 index 0000000..4875f4f --- /dev/null +++ b/.import/Load.svg-b891ac6d40504b3c1e708e068830a830.md5 @@ -0,0 +1,3 @@ +source_md5="bbc7c14d2ff9ceb8dd93b94af5f70304" +dest_md5="cbce485262bc3ef62228ed8828d103bd" + diff --git a/.import/Load.svg-b891ac6d40504b3c1e708e068830a830.stex b/.import/Load.svg-b891ac6d40504b3c1e708e068830a830.stex new file mode 100644 index 0000000..29c6ffd Binary files /dev/null and b/.import/Load.svg-b891ac6d40504b3c1e708e068830a830.stex differ diff --git a/.import/Load.svg-eeb120247bcce6f3a1ac32d8d91aaacb.md5 b/.import/Load.svg-eeb120247bcce6f3a1ac32d8d91aaacb.md5 new file mode 100644 index 0000000..4875f4f --- /dev/null +++ b/.import/Load.svg-eeb120247bcce6f3a1ac32d8d91aaacb.md5 @@ -0,0 +1,3 @@ +source_md5="bbc7c14d2ff9ceb8dd93b94af5f70304" +dest_md5="cbce485262bc3ef62228ed8828d103bd" + diff --git a/.import/Loop.svg-8ee360409bbe3485d0005d5377340ca3.md5 b/.import/Loop.svg-8ee360409bbe3485d0005d5377340ca3.md5 new file mode 100644 index 0000000..800f63c --- /dev/null +++ b/.import/Loop.svg-8ee360409bbe3485d0005d5377340ca3.md5 @@ -0,0 +1,3 @@ +source_md5="2375328291ff902c7beb3e59cd28ec43" +dest_md5="760bf8bc33231a4553498d21d0db4528" + diff --git a/.import/Loop.svg-8ee360409bbe3485d0005d5377340ca3.stex b/.import/Loop.svg-8ee360409bbe3485d0005d5377340ca3.stex new file mode 100644 index 0000000..afc5892 Binary files /dev/null and b/.import/Loop.svg-8ee360409bbe3485d0005d5377340ca3.stex differ diff --git a/.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.md5 b/.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.md5 new file mode 100644 index 0000000..800f63c --- /dev/null +++ b/.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.md5 @@ -0,0 +1,3 @@ +source_md5="2375328291ff902c7beb3e59cd28ec43" +dest_md5="760bf8bc33231a4553498d21d0db4528" + diff --git a/.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.stex b/.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.stex new file mode 100644 index 0000000..afc5892 Binary files /dev/null and b/.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.stex differ diff --git a/.import/PageFirst.svg-1d4ebb05676555cf073dc8f7ba2443bf.md5 b/.import/PageFirst.svg-1d4ebb05676555cf073dc8f7ba2443bf.md5 new file mode 100644 index 0000000..c19140b --- /dev/null +++ b/.import/PageFirst.svg-1d4ebb05676555cf073dc8f7ba2443bf.md5 @@ -0,0 +1,3 @@ +source_md5="f5e8408d52c8bae4d1f290b29bfdb256" +dest_md5="fa05bf7bc0862070fb4996ecc2786e5f" + diff --git a/.import/PageFirst.svg-1d4ebb05676555cf073dc8f7ba2443bf.stex b/.import/PageFirst.svg-1d4ebb05676555cf073dc8f7ba2443bf.stex new file mode 100644 index 0000000..50febfc Binary files /dev/null and b/.import/PageFirst.svg-1d4ebb05676555cf073dc8f7ba2443bf.stex differ diff --git a/.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.md5 b/.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.md5 new file mode 100644 index 0000000..c19140b --- /dev/null +++ b/.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.md5 @@ -0,0 +1,3 @@ +source_md5="f5e8408d52c8bae4d1f290b29bfdb256" +dest_md5="fa05bf7bc0862070fb4996ecc2786e5f" + diff --git a/.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.stex b/.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.stex new file mode 100644 index 0000000..50febfc Binary files /dev/null and b/.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.stex differ diff --git a/.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.md5 b/.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.md5 new file mode 100644 index 0000000..c02cdda --- /dev/null +++ b/.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.md5 @@ -0,0 +1,3 @@ +source_md5="4d617f72f60f36ef62a74ba84c06a6f4" +dest_md5="47b53d238d38af05de853d750b4169b8" + diff --git a/.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.stex b/.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.stex new file mode 100644 index 0000000..53dcc23 Binary files /dev/null and b/.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.stex differ diff --git a/.import/PageLast.svg-d8f53dd716408da14840ed86a0f0153c.md5 b/.import/PageLast.svg-d8f53dd716408da14840ed86a0f0153c.md5 new file mode 100644 index 0000000..c02cdda --- /dev/null +++ b/.import/PageLast.svg-d8f53dd716408da14840ed86a0f0153c.md5 @@ -0,0 +1,3 @@ +source_md5="4d617f72f60f36ef62a74ba84c06a6f4" +dest_md5="47b53d238d38af05de853d750b4169b8" + diff --git a/.import/PageLast.svg-d8f53dd716408da14840ed86a0f0153c.stex b/.import/PageLast.svg-d8f53dd716408da14840ed86a0f0153c.stex new file mode 100644 index 0000000..53dcc23 Binary files /dev/null and b/.import/PageLast.svg-d8f53dd716408da14840ed86a0f0153c.stex differ diff --git a/.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.md5 b/.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.md5 new file mode 100644 index 0000000..d0095cc --- /dev/null +++ b/.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.md5 @@ -0,0 +1,3 @@ +source_md5="c9c33f78479dae49abfca45607b4db98" +dest_md5="f4d4b0d576af95c9ed3da11bb338bed0" + diff --git a/.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.stex b/.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.stex new file mode 100644 index 0000000..cd31e35 Binary files /dev/null and b/.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.stex differ diff --git a/.import/PageNext.svg-940c2821b0f23650a59c1ba19d5be478.md5 b/.import/PageNext.svg-940c2821b0f23650a59c1ba19d5be478.md5 new file mode 100644 index 0000000..d0095cc --- /dev/null +++ b/.import/PageNext.svg-940c2821b0f23650a59c1ba19d5be478.md5 @@ -0,0 +1,3 @@ +source_md5="c9c33f78479dae49abfca45607b4db98" +dest_md5="f4d4b0d576af95c9ed3da11bb338bed0" + diff --git a/.import/PageNext.svg-940c2821b0f23650a59c1ba19d5be478.stex b/.import/PageNext.svg-940c2821b0f23650a59c1ba19d5be478.stex new file mode 100644 index 0000000..cd31e35 Binary files /dev/null and b/.import/PageNext.svg-940c2821b0f23650a59c1ba19d5be478.stex differ diff --git a/.import/PagePrevious.svg-f372e23388737eeac4b6022dc67c18e1.md5 b/.import/PagePrevious.svg-f372e23388737eeac4b6022dc67c18e1.md5 new file mode 100644 index 0000000..e64c353 --- /dev/null +++ b/.import/PagePrevious.svg-f372e23388737eeac4b6022dc67c18e1.md5 @@ -0,0 +1,3 @@ +source_md5="712646fe832224d1831ed0097f1ce88a" +dest_md5="b84ea79eec88678582d309f6e637715d" + diff --git a/.import/PagePrevious.svg-f372e23388737eeac4b6022dc67c18e1.stex b/.import/PagePrevious.svg-f372e23388737eeac4b6022dc67c18e1.stex new file mode 100644 index 0000000..c9607bf Binary files /dev/null and b/.import/PagePrevious.svg-f372e23388737eeac4b6022dc67c18e1.stex differ diff --git a/.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.md5 b/.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.md5 new file mode 100644 index 0000000..e64c353 --- /dev/null +++ b/.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.md5 @@ -0,0 +1,3 @@ +source_md5="712646fe832224d1831ed0097f1ce88a" +dest_md5="b84ea79eec88678582d309f6e637715d" + diff --git a/.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.stex b/.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.stex new file mode 100644 index 0000000..c9607bf Binary files /dev/null and b/.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.stex differ diff --git a/.import/Play.svg-8c7939f540eddb3dd8ff2d79d7e6ea0e.md5 b/.import/Play.svg-8c7939f540eddb3dd8ff2d79d7e6ea0e.md5 new file mode 100644 index 0000000..4347303 --- /dev/null +++ b/.import/Play.svg-8c7939f540eddb3dd8ff2d79d7e6ea0e.md5 @@ -0,0 +1,3 @@ +source_md5="203abe73750d3ffae1fd972a9f015c8f" +dest_md5="aca89ac14c2ae3576e35cfcc4f15c6a1" + diff --git a/.import/Play.svg-8c7939f540eddb3dd8ff2d79d7e6ea0e.stex b/.import/Play.svg-8c7939f540eddb3dd8ff2d79d7e6ea0e.stex new file mode 100644 index 0000000..a1c7744 Binary files /dev/null and b/.import/Play.svg-8c7939f540eddb3dd8ff2d79d7e6ea0e.stex differ diff --git a/.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.md5 b/.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.md5 new file mode 100644 index 0000000..4347303 --- /dev/null +++ b/.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.md5 @@ -0,0 +1,3 @@ +source_md5="203abe73750d3ffae1fd972a9f015c8f" +dest_md5="aca89ac14c2ae3576e35cfcc4f15c6a1" + diff --git a/.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.stex b/.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.stex new file mode 100644 index 0000000..a1c7744 Binary files /dev/null and b/.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.stex differ diff --git a/.import/Reload.svg-1c2e8d0f8dfad3db7f83536ae2e23ef7.md5 b/.import/Reload.svg-1c2e8d0f8dfad3db7f83536ae2e23ef7.md5 new file mode 100644 index 0000000..44a748f --- /dev/null +++ b/.import/Reload.svg-1c2e8d0f8dfad3db7f83536ae2e23ef7.md5 @@ -0,0 +1,3 @@ +source_md5="d1c4e487fcaff55ae35cd5b5663309cd" +dest_md5="1967be6cc6db251a339c8df9bb25644a" + diff --git a/.import/Reload.svg-1c2e8d0f8dfad3db7f83536ae2e23ef7.stex b/.import/Reload.svg-1c2e8d0f8dfad3db7f83536ae2e23ef7.stex new file mode 100644 index 0000000..ec805ec Binary files /dev/null and b/.import/Reload.svg-1c2e8d0f8dfad3db7f83536ae2e23ef7.stex differ diff --git a/.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.md5 b/.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.md5 new file mode 100644 index 0000000..44a748f --- /dev/null +++ b/.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.md5 @@ -0,0 +1,3 @@ +source_md5="d1c4e487fcaff55ae35cd5b5663309cd" +dest_md5="1967be6cc6db251a339c8df9bb25644a" + diff --git a/.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.stex b/.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.stex new file mode 100644 index 0000000..ec805ec Binary files /dev/null and b/.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.stex differ diff --git a/.import/Reload.svg-f674b6d3b397cca5a3b1071a190f7688.md5 b/.import/Reload.svg-f674b6d3b397cca5a3b1071a190f7688.md5 new file mode 100644 index 0000000..44a748f --- /dev/null +++ b/.import/Reload.svg-f674b6d3b397cca5a3b1071a190f7688.md5 @@ -0,0 +1,3 @@ +source_md5="d1c4e487fcaff55ae35cd5b5663309cd" +dest_md5="1967be6cc6db251a339c8df9bb25644a" + diff --git a/.import/Reload.svg-f674b6d3b397cca5a3b1071a190f7688.stex b/.import/Reload.svg-f674b6d3b397cca5a3b1071a190f7688.stex new file mode 100644 index 0000000..ec805ec Binary files /dev/null and b/.import/Reload.svg-f674b6d3b397cca5a3b1071a190f7688.stex differ diff --git a/.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.md5 b/.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.md5 new file mode 100644 index 0000000..c4e715c --- /dev/null +++ b/.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.md5 @@ -0,0 +1,3 @@ +source_md5="81e1b60b172fe7ba6f023aa395f8bc09" +dest_md5="5350ccff34316341a632628c86b61d2c" + diff --git a/.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.stex b/.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.stex new file mode 100644 index 0000000..fbc9068 Binary files /dev/null and b/.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.stex differ diff --git a/.import/Remove.svg-ea31aace783a4729f346efde9c35db03.md5 b/.import/Remove.svg-ea31aace783a4729f346efde9c35db03.md5 new file mode 100644 index 0000000..c4e715c --- /dev/null +++ b/.import/Remove.svg-ea31aace783a4729f346efde9c35db03.md5 @@ -0,0 +1,3 @@ +source_md5="81e1b60b172fe7ba6f023aa395f8bc09" +dest_md5="5350ccff34316341a632628c86b61d2c" + diff --git a/.import/Remove.svg-ea31aace783a4729f346efde9c35db03.stex b/.import/Remove.svg-ea31aace783a4729f346efde9c35db03.stex new file mode 100644 index 0000000..fbc9068 Binary files /dev/null and b/.import/Remove.svg-ea31aace783a4729f346efde9c35db03.stex differ diff --git a/.import/RemoveInternal.svg-8a847987db6ed6b5d5f83247dff72ecf.md5 b/.import/RemoveInternal.svg-8a847987db6ed6b5d5f83247dff72ecf.md5 new file mode 100644 index 0000000..08a7261 --- /dev/null +++ b/.import/RemoveInternal.svg-8a847987db6ed6b5d5f83247dff72ecf.md5 @@ -0,0 +1,3 @@ +source_md5="d00702b5a62d9966f9e8e4d2ae27e06a" +dest_md5="c60d1389f464455ed7e03a78705f3f35" + diff --git a/.import/Slot.svg-5706c544ba662d356da7150fb8d57b32.md5 b/.import/Slot.svg-5706c544ba662d356da7150fb8d57b32.md5 new file mode 100644 index 0000000..2a6a6d7 --- /dev/null +++ b/.import/Slot.svg-5706c544ba662d356da7150fb8d57b32.md5 @@ -0,0 +1,3 @@ +source_md5="f8eeaa2fa9673b236aba5bff55843964" +dest_md5="b45588cccdb8ca3d9c47ee7053a247ed" + diff --git a/.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.md5 b/.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.md5 new file mode 100644 index 0000000..f978c4b --- /dev/null +++ b/.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.md5 @@ -0,0 +1,3 @@ +source_md5="94f6c9ebc59f743f6fd02763e0ed9655" +dest_md5="b1222fcba24045274cbee51f959e4dc5" + diff --git a/.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.stex b/.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.stex new file mode 100644 index 0000000..0c5dfe5 Binary files /dev/null and b/.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.stex differ diff --git a/.import/SoundFile.svg-b9aa8d928fe9e56fb1175f305a1afe71.md5 b/.import/SoundFile.svg-b9aa8d928fe9e56fb1175f305a1afe71.md5 new file mode 100644 index 0000000..f978c4b --- /dev/null +++ b/.import/SoundFile.svg-b9aa8d928fe9e56fb1175f305a1afe71.md5 @@ -0,0 +1,3 @@ +source_md5="94f6c9ebc59f743f6fd02763e0ed9655" +dest_md5="b1222fcba24045274cbee51f959e4dc5" + diff --git a/.import/SoundFile.svg-b9aa8d928fe9e56fb1175f305a1afe71.stex b/.import/SoundFile.svg-b9aa8d928fe9e56fb1175f305a1afe71.stex new file mode 100644 index 0000000..0c5dfe5 Binary files /dev/null and b/.import/SoundFile.svg-b9aa8d928fe9e56fb1175f305a1afe71.stex differ diff --git a/.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.md5 b/.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.md5 new file mode 100644 index 0000000..2b2e449 --- /dev/null +++ b/.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.md5 @@ -0,0 +1,3 @@ +source_md5="1cd676f27b20e07b3cfd4e17e7083bcf" +dest_md5="12c7ff85948d881c3d6c5226a9fa5d05" + diff --git a/.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.stex b/.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.stex new file mode 100644 index 0000000..d2cd024 Binary files /dev/null and b/.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.stex differ diff --git a/.import/Stop.svg-d380ef61b69b60538d594891884c342c.md5 b/.import/Stop.svg-d380ef61b69b60538d594891884c342c.md5 new file mode 100644 index 0000000..2b2e449 --- /dev/null +++ b/.import/Stop.svg-d380ef61b69b60538d594891884c342c.md5 @@ -0,0 +1,3 @@ +source_md5="1cd676f27b20e07b3cfd4e17e7083bcf" +dest_md5="12c7ff85948d881c3d6c5226a9fa5d05" + diff --git a/.import/Stop.svg-d380ef61b69b60538d594891884c342c.stex b/.import/Stop.svg-d380ef61b69b60538d594891884c342c.stex new file mode 100644 index 0000000..d2cd024 Binary files /dev/null and b/.import/Stop.svg-d380ef61b69b60538d594891884c342c.stex differ diff --git a/.import/VisualShaderPort-45x45.svg-fbe76dcf17ea243799ce4bd3779c2ee8.md5 b/.import/VisualShaderPort-45x45.svg-fbe76dcf17ea243799ce4bd3779c2ee8.md5 new file mode 100644 index 0000000..12c29bd --- /dev/null +++ b/.import/VisualShaderPort-45x45.svg-fbe76dcf17ea243799ce4bd3779c2ee8.md5 @@ -0,0 +1,3 @@ +source_md5="ef4181c051ab2b5a7d07a4e22e13dd5b" +dest_md5="6a076b90f87acbbc6dabe1b6d577b886" + diff --git a/.import/VisualShaderPort.svg-3798c29f8d8520abff527eed1d4358be.md5 b/.import/VisualShaderPort.svg-3798c29f8d8520abff527eed1d4358be.md5 new file mode 100644 index 0000000..6494499 --- /dev/null +++ b/.import/VisualShaderPort.svg-3798c29f8d8520abff527eed1d4358be.md5 @@ -0,0 +1,3 @@ +source_md5="da63afc7c876f808b47edcd2547c24d8" +dest_md5="6a076b90f87acbbc6dabe1b6d577b886" + diff --git a/.import/VisualShaderPort.svg-3798c29f8d8520abff527eed1d4358be.stex b/.import/VisualShaderPort.svg-3798c29f8d8520abff527eed1d4358be.stex new file mode 100644 index 0000000..63fb324 Binary files /dev/null and b/.import/VisualShaderPort.svg-3798c29f8d8520abff527eed1d4358be.stex differ diff --git a/.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.md5 b/.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.md5 new file mode 100644 index 0000000..6494499 --- /dev/null +++ b/.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.md5 @@ -0,0 +1,3 @@ +source_md5="da63afc7c876f808b47edcd2547c24d8" +dest_md5="6a076b90f87acbbc6dabe1b6d577b886" + diff --git a/.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.stex b/.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.stex new file mode 100644 index 0000000..63fb324 Binary files /dev/null and b/.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.stex differ diff --git a/.import/VisualShaderPort.svg-fb5ce1fc9937ef528ca32f09bc52e638.md5 b/.import/VisualShaderPort.svg-fb5ce1fc9937ef528ca32f09bc52e638.md5 new file mode 100644 index 0000000..6494499 --- /dev/null +++ b/.import/VisualShaderPort.svg-fb5ce1fc9937ef528ca32f09bc52e638.md5 @@ -0,0 +1,3 @@ +source_md5="da63afc7c876f808b47edcd2547c24d8" +dest_md5="6a076b90f87acbbc6dabe1b6d577b886" + diff --git a/.import/VisualShaderPort.svg-fb5ce1fc9937ef528ca32f09bc52e638.stex b/.import/VisualShaderPort.svg-fb5ce1fc9937ef528ca32f09bc52e638.stex new file mode 100644 index 0000000..63fb324 Binary files /dev/null and b/.import/VisualShaderPort.svg-fb5ce1fc9937ef528ca32f09bc52e638.stex differ diff --git a/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5 b/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5 new file mode 100644 index 0000000..5328bc7 --- /dev/null +++ b/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.md5 @@ -0,0 +1,3 @@ +source_md5="47313fa4c47a9963fddd764e1ec6e4a8" +dest_md5="26ea799ea0a3da9e753b3ebe822e0570" + diff --git a/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex b/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex new file mode 100644 index 0000000..71f6913 Binary files /dev/null and b/.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex differ diff --git a/Assets/Icons/Add.svg b/Assets/Icons/Add.svg new file mode 100644 index 0000000..afad08a --- /dev/null +++ b/Assets/Icons/Add.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/Add.svg.import b/Assets/Icons/Add.svg.import new file mode 100644 index 0000000..cb24e77 --- /dev/null +++ b/Assets/Icons/Add.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Add.svg" +dest_files=[ "res://.import/Add.svg-078ad3409bd2c967c3fab28fa9bba462.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/Empty.svg b/Assets/Icons/Empty.svg new file mode 100644 index 0000000..781b0c2 --- /dev/null +++ b/Assets/Icons/Empty.svg @@ -0,0 +1,34 @@ + + + + + diff --git a/Assets/Icons/Empty.svg.import b/Assets/Icons/Empty.svg.import new file mode 100644 index 0000000..9702e76 --- /dev/null +++ b/Assets/Icons/Empty.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Empty.svg" +dest_files=[ "res://.import/Empty.svg-c6437793b6babc478a4cbc2e94775d97.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/ImageTexture.svg b/Assets/Icons/ImageTexture.svg new file mode 100644 index 0000000..013e847 --- /dev/null +++ b/Assets/Icons/ImageTexture.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/ImageTexture.svg.import b/Assets/Icons/ImageTexture.svg.import new file mode 100644 index 0000000..71f778a --- /dev/null +++ b/Assets/Icons/ImageTexture.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/ImageTexture.svg" +dest_files=[ "res://.import/ImageTexture.svg-174d19b4464e8baaf972427d76ecb3c0.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/Loop.svg b/Assets/Icons/Loop.svg new file mode 100644 index 0000000..7fd8561 --- /dev/null +++ b/Assets/Icons/Loop.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/Loop.svg.import b/Assets/Icons/Loop.svg.import new file mode 100644 index 0000000..23da812 --- /dev/null +++ b/Assets/Icons/Loop.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Loop.svg" +dest_files=[ "res://.import/Loop.svg-af45fae773fa119d55ae09a6cbdbc294.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/PageFirst.svg b/Assets/Icons/PageFirst.svg new file mode 100644 index 0000000..ab5cd2c --- /dev/null +++ b/Assets/Icons/PageFirst.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/PageFirst.svg.import b/Assets/Icons/PageFirst.svg.import new file mode 100644 index 0000000..fb7b288 --- /dev/null +++ b/Assets/Icons/PageFirst.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/PageFirst.svg" +dest_files=[ "res://.import/PageFirst.svg-544592dc079731eb39f72304f7fd971c.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/PageLast.svg b/Assets/Icons/PageLast.svg new file mode 100644 index 0000000..0bc8504 --- /dev/null +++ b/Assets/Icons/PageLast.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/PageLast.svg.import b/Assets/Icons/PageLast.svg.import new file mode 100644 index 0000000..795f2ae --- /dev/null +++ b/Assets/Icons/PageLast.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/PageLast.svg" +dest_files=[ "res://.import/PageLast.svg-2c28d94bc597ae2dcc442d6177cc2bb6.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/PageNext.svg b/Assets/Icons/PageNext.svg new file mode 100644 index 0000000..2c3d032 --- /dev/null +++ b/Assets/Icons/PageNext.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/PageNext.svg.import b/Assets/Icons/PageNext.svg.import new file mode 100644 index 0000000..1e69806 --- /dev/null +++ b/Assets/Icons/PageNext.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/PageNext.svg" +dest_files=[ "res://.import/PageNext.svg-517e9005de3dcfe787034e3194d91655.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/PagePrevious.svg b/Assets/Icons/PagePrevious.svg new file mode 100644 index 0000000..37adc85 --- /dev/null +++ b/Assets/Icons/PagePrevious.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/PagePrevious.svg.import b/Assets/Icons/PagePrevious.svg.import new file mode 100644 index 0000000..b38a05d --- /dev/null +++ b/Assets/Icons/PagePrevious.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/PagePrevious.svg" +dest_files=[ "res://.import/PagePrevious.svg-feeff7af0e4e433a1b43e0be160f7367.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/Play.svg b/Assets/Icons/Play.svg new file mode 100644 index 0000000..0be543d --- /dev/null +++ b/Assets/Icons/Play.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/Play.svg.import b/Assets/Icons/Play.svg.import new file mode 100644 index 0000000..59548c8 --- /dev/null +++ b/Assets/Icons/Play.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Play.svg" +dest_files=[ "res://.import/Play.svg-dc9d1e4faf0a73efbad4eb8b6934168b.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/Reload.svg b/Assets/Icons/Reload.svg new file mode 100644 index 0000000..1200df1 --- /dev/null +++ b/Assets/Icons/Reload.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/Reload.svg.import b/Assets/Icons/Reload.svg.import new file mode 100644 index 0000000..7cea25f --- /dev/null +++ b/Assets/Icons/Reload.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Reload.svg" +dest_files=[ "res://.import/Reload.svg-5d27a5a87adf6af4173997cf00d3fff9.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/Remove.svg b/Assets/Icons/Remove.svg new file mode 100644 index 0000000..5bcdf8e --- /dev/null +++ b/Assets/Icons/Remove.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/Remove.svg.import b/Assets/Icons/Remove.svg.import new file mode 100644 index 0000000..6352336 --- /dev/null +++ b/Assets/Icons/Remove.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Remove.svg" +dest_files=[ "res://.import/Remove.svg-02e9ca30c6ec038cd7c3502cdedc9620.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/SoundFile.svg b/Assets/Icons/SoundFile.svg new file mode 100644 index 0000000..b0e5365 --- /dev/null +++ b/Assets/Icons/SoundFile.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + diff --git a/Assets/Icons/SoundFile.svg.import b/Assets/Icons/SoundFile.svg.import new file mode 100644 index 0000000..769750f --- /dev/null +++ b/Assets/Icons/SoundFile.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/SoundFile.svg" +dest_files=[ "res://.import/SoundFile.svg-770727f6e4a267c4889f5e9c0cdb3689.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/Stop.svg b/Assets/Icons/Stop.svg new file mode 100644 index 0000000..2059eab --- /dev/null +++ b/Assets/Icons/Stop.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/Stop.svg.import b/Assets/Icons/Stop.svg.import new file mode 100644 index 0000000..8857523 --- /dev/null +++ b/Assets/Icons/Stop.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/Stop.svg" +dest_files=[ "res://.import/Stop.svg-0ec47ceeabe82b8c8446cf08fec61e76.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Icons/VisualShaderPort.svg b/Assets/Icons/VisualShaderPort.svg new file mode 100644 index 0000000..5311513 --- /dev/null +++ b/Assets/Icons/VisualShaderPort.svg @@ -0,0 +1 @@ + diff --git a/Assets/Icons/VisualShaderPort.svg.import b/Assets/Icons/VisualShaderPort.svg.import new file mode 100644 index 0000000..8b1b122 --- /dev/null +++ b/Assets/Icons/VisualShaderPort.svg.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://Assets/Icons/VisualShaderPort.svg" +dest_files=[ "res://.import/VisualShaderPort.svg-6e3eb9d7ced32eeb5e36239d0adf0a72.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=true +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=true +svg/scale=1.0 diff --git a/Assets/Roboto-Bold.ttf b/Assets/Roboto-Bold.ttf new file mode 100644 index 0000000..3685c7a Binary files /dev/null and b/Assets/Roboto-Bold.ttf differ diff --git a/Resources/NormalFrame.tres b/Resources/NormalFrame.tres new file mode 100644 index 0000000..59b7164 --- /dev/null +++ b/Resources/NormalFrame.tres @@ -0,0 +1,18 @@ +[gd_resource type="StyleBoxFlat" format=2] + +[resource] +content_margin_left = 12.0 +content_margin_right = 12.0 +content_margin_top = 25.0 +content_margin_bottom = 5.0 +bg_color = Color( 0.270588, 0.290196, 0.341176, 1 ) +border_width_top = 24 +border_color = Color( 0.533333, 0.615686, 0.776471, 1 ) +border_blend = true +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +shadow_color = Color( 0, 0, 0, 0.392157 ) +shadow_size = 3 +shadow_offset = Vector2( 2, 3 ) diff --git a/Resources/SelectedFrame.tres b/Resources/SelectedFrame.tres new file mode 100644 index 0000000..ec8fa72 --- /dev/null +++ b/Resources/SelectedFrame.tres @@ -0,0 +1,18 @@ +[gd_resource type="StyleBoxFlat" format=2] + +[resource] +content_margin_left = 12.0 +content_margin_right = 12.0 +content_margin_top = 25.0 +content_margin_bottom = 5.0 +bg_color = Color( 0.74902, 0.388235, 0.180392, 1 ) +border_width_top = 24 +border_color = Color( 1, 0.890196, 0.827451, 1 ) +border_blend = true +corner_radius_top_left = 4 +corner_radius_top_right = 4 +corner_radius_bottom_right = 4 +corner_radius_bottom_left = 4 +shadow_color = Color( 0, 0, 0, 0.392157 ) +shadow_size = 5 +shadow_offset = Vector2( 4, 5 ) diff --git a/Resources/default_env.tres b/Resources/default_env.tres new file mode 100644 index 0000000..20207a4 --- /dev/null +++ b/Resources/default_env.tres @@ -0,0 +1,7 @@ +[gd_resource type="Environment" load_steps=2 format=2] + +[sub_resource type="ProceduralSky" id=1] + +[resource] +background_mode = 2 +background_sky = SubResource( 1 ) diff --git a/Resources/styleboxflat.tres b/Resources/styleboxflat.tres new file mode 100644 index 0000000..6b31e66 --- /dev/null +++ b/Resources/styleboxflat.tres @@ -0,0 +1,4 @@ +[gd_resource type="StyleBoxFlat" format=2] + +[resource] +bg_color = Color( 0.141176, 0.141176, 0.141176, 1 ) diff --git a/Resources/theme.tres b/Resources/theme.tres new file mode 100644 index 0000000..8a44629 --- /dev/null +++ b/Resources/theme.tres @@ -0,0 +1,3 @@ +[gd_resource type="Theme" format=2] + +[resource] diff --git a/Scenes/DisplayDialog.tscn b/Scenes/DisplayDialog.tscn new file mode 100644 index 0000000..f8e93ba --- /dev/null +++ b/Scenes/DisplayDialog.tscn @@ -0,0 +1,213 @@ +[gd_scene load_steps=15 format=2] + +[ext_resource path="res://Scripts/DisplayDialog.gd" type="Script" id=1] +[ext_resource path="res://Assets/Icons/Remove.svg" type="Texture" id=2] +[ext_resource path="res://Assets/Icons/PagePrevious.svg" type="Texture" id=3] +[ext_resource path="res://Assets/Icons/PageLast.svg" type="Texture" id=4] +[ext_resource path="res://Assets/Icons/PageNext.svg" type="Texture" id=5] +[ext_resource path="res://Assets/Icons/Stop.svg" type="Texture" id=6] +[ext_resource path="res://Assets/Icons/Play.svg" type="Texture" id=7] +[ext_resource path="res://Assets/Icons/PageFirst.svg" type="Texture" id=8] +[ext_resource path="res://Assets/Icons/Loop.svg" type="Texture" id=9] +[ext_resource path="res://Assets/Icons/Reload.svg" type="Texture" id=10] +[ext_resource path="res://Assets/Icons/ImageTexture.svg" type="Texture" id=11] +[ext_resource path="res://Assets/Icons/SoundFile.svg" type="Texture" id=12] + +[sub_resource type="DynamicFontData" id=1] +font_path = "res://Assets/Roboto-Bold.ttf" + +[sub_resource type="DynamicFont" id=2] +size = 30 +outline_size = 2 +outline_color = Color( 0, 0, 0, 1 ) +use_filter = true +font_data = SubResource( 1 ) + +[node name="DisplayDialog" type="WindowDialog"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_right = -88.0 +margin_bottom = -53.0 +rect_min_size = Vector2( 100, 100 ) +resizable = true +script = ExtResource( 1 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 + +[node name="Control" type="Control" parent="VBoxContainer"] +margin_right = 1192.0 +margin_bottom = 671.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ColorRect" type="ColorRect" parent="VBoxContainer/Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +color = Color( 0, 0, 0, 1 ) + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +expand = true +stretch_mode = 6 + +[node name="Subtitle" type="Label" parent="VBoxContainer/Control"] +anchor_top = 1.0 +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 128.0 +margin_top = -132.0 +margin_right = -128.0 +custom_colors/font_color = Color( 1, 0.976471, 0.87451, 1 ) +custom_colors/font_outline_modulate = Color( 0, 0, 0, 1 ) +custom_colors/font_color_shadow = Color( 0, 0, 0, 1 ) +custom_constants/shadow_as_outline = 1 +custom_fonts/font = SubResource( 2 ) +text = "pdvjpnj\\\\npn +njpn pkn kn pkn " +align = 1 +valign = 1 +clip_text = true +max_lines_visible = 2 + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 675.0 +margin_right = 1192.0 +margin_bottom = 715.0 +alignment = 1 + +[node name="SubtitleEdit" type="TextEdit" parent="VBoxContainer/HBoxContainer"] +margin_right = 679.0 +margin_bottom = 40.0 +rect_min_size = Vector2( 0, 22 ) +hint_tooltip = "Subtitles" +size_flags_horizontal = 3 +wrap_enabled = true + +[node name="FirstButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 683.0 +margin_right = 707.0 +margin_bottom = 40.0 +hint_tooltip = "First frame" +icon = ExtResource( 8 ) + +[node name="PrevButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 711.0 +margin_right = 735.0 +margin_bottom = 40.0 +hint_tooltip = " Previous frame" +icon = ExtResource( 3 ) + +[node name="PlayButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 739.0 +margin_right = 767.0 +margin_bottom = 40.0 +hint_tooltip = "Play/pause" +icon = ExtResource( 7 ) + +[node name="StopButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 771.0 +margin_right = 799.0 +margin_bottom = 40.0 +hint_tooltip = "Stop playback" +icon = ExtResource( 6 ) + +[node name="NextButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 803.0 +margin_right = 827.0 +margin_bottom = 40.0 +hint_tooltip = " Next frame" +icon = ExtResource( 5 ) + +[node name="LastButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 831.0 +margin_right = 855.0 +margin_bottom = 40.0 +hint_tooltip = "Last frame" +icon = ExtResource( 4 ) + +[node name="LoopButton" type="CheckButton" parent="VBoxContainer/HBoxContainer"] +margin_left = 859.0 +margin_right = 951.0 +margin_bottom = 40.0 +hint_tooltip = "Loop" +icon = ExtResource( 9 ) + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] +margin_left = 955.0 +margin_top = 13.0 +margin_right = 1018.0 +margin_bottom = 27.0 +text = "Duration: " +valign = 1 + +[node name="SpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] +margin_left = 1022.0 +margin_right = 1096.0 +margin_bottom = 40.0 +hint_tooltip = "Frame duration (in seconds)" +min_value = 0.1 +max_value = 60.0 +step = 0.1 +page = 0.5 +value = 1.0 +align = 3 +suffix = "s" + +[node name="LoadButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 1100.0 +margin_right = 1128.0 +margin_bottom = 40.0 +hint_tooltip = "Load image from file" +icon = ExtResource( 11 ) + +[node name="SoundButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 1132.0 +margin_right = 1160.0 +margin_bottom = 40.0 +hint_tooltip = "Load sound from file" +icon = ExtResource( 12 ) + +[node name="DelSoundButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 209.0 +margin_right = 237.0 +margin_bottom = 24.0 +hint_tooltip = "Remove sound" +icon = ExtResource( 2 ) + +[node name="ReloadButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 1164.0 +margin_right = 1192.0 +margin_bottom = 40.0 +hint_tooltip = "Reload image and sound" +icon = ExtResource( 10 ) +icon_align = 1 + +[node name="PlayTimer" type="Timer" parent="."] + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="."] + +[connection signal="about_to_show" from="." to="." method="_on_DisplayDialog_about_to_show"] +[connection signal="popup_hide" from="." to="." method="_on_DisplayDialog_popup_hide"] +[connection signal="gui_input" from="VBoxContainer/Control/TextureRect" to="." method="_on_TextureRect_gui_input"] +[connection signal="text_changed" from="VBoxContainer/HBoxContainer/SubtitleEdit" to="." method="_on_SubtitleEdit_text_changed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/FirstButton" to="." method="_on_FirstButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/PrevButton" to="." method="_on_PrevButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/PlayButton" to="." method="_on_PlayButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/StopButton" to="." method="_on_StopButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/NextButton" to="." method="_on_NextButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/LastButton" to="." method="_on_LastButton_pressed"] +[connection signal="toggled" from="VBoxContainer/HBoxContainer/LoopButton" to="." method="_on_LoopButton_toggled"] +[connection signal="focus_entered" from="VBoxContainer/HBoxContainer/SpinBox" to="." method="_on_SpinBox_focus_entered"] +[connection signal="value_changed" from="VBoxContainer/HBoxContainer/SpinBox" to="." method="_on_SpinBox_value_changed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/LoadButton" to="." method="_on_LoadButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/SoundButton" to="." method="_on_SoundButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/DelSoundButton" to="." method="_on_DelSoundButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/ReloadButton" to="." method="_on_ReloadButton_pressed"] +[connection signal="timeout" from="PlayTimer" to="." method="_on_PlayTimer_timeout"] diff --git a/Scenes/GraphEdit.tscn b/Scenes/GraphEdit.tscn new file mode 100644 index 0000000..238f3dd --- /dev/null +++ b/Scenes/GraphEdit.tscn @@ -0,0 +1,121 @@ +[gd_scene load_steps=5 format=2] + +[ext_resource path="res://Scenes/DisplayDialog.tscn" type="PackedScene" id=1] +[ext_resource path="res://Scripts/GraphEdit.gd" type="Script" id=2] +[ext_resource path="res://Assets/Icons/Play.svg" type="Texture" id=3] +[ext_resource path="res://Assets/Icons/Add.svg" type="Texture" id=4] + +[node name="Graph" type="GraphEdit"] +anchor_right = 1.0 +anchor_bottom = 1.0 +right_disconnects = true +use_snap = false +script = ExtResource( 2 ) + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +margin_left = 261.0 +margin_top = 9.0 +margin_right = 392.0 +margin_bottom = 33.0 +__meta__ = { +"_edit_group_": true +} + +[node name="GridColsSpinBox" type="SpinBox" parent="HBoxContainer"] +margin_right = 74.0 +margin_bottom = 24.0 +hint_tooltip = "Number of columns in grid" +min_value = 1.0 +value = 5.0 + +[node name="AddButton" type="Button" parent="HBoxContainer"] +margin_left = 78.0 +margin_right = 106.0 +margin_bottom = 24.0 +hint_tooltip = "Add a new frame" +icon = ExtResource( 4 ) + +[node name="PlayButton" type="Button" parent="HBoxContainer"] +margin_left = 110.0 +margin_right = 138.0 +margin_bottom = 24.0 +hint_tooltip = "Play from selected frame" +disabled = true +icon = ExtResource( 3 ) + +[node name="DebugButton" type="Button" parent="HBoxContainer"] +visible = false +margin_left = 142.0 +margin_right = 195.0 +margin_bottom = 24.0 +text = "Debug" + +[node name="DisplayDialog" parent="." instance=ExtResource( 1 )] + +[node name="OpenImgFileDialog" type="FileDialog" parent="."] +margin_left = -632.0 +margin_top = 64.0 +margin_right = -48.0 +margin_bottom = 526.0 +popup_exclusive = true +window_title = "Open a File" +resizable = true +mode = 0 +access = 2 +filters = PoolStringArray( "*.jpg, *.jpeg", "*.png", "*.bmp" ) + +[node name="OpenSndFileDialog" type="FileDialog" parent="."] +margin_left = -632.0 +margin_top = 64.0 +margin_right = -48.0 +margin_bottom = 526.0 +popup_exclusive = true +window_title = "Open a File" +resizable = true +mode = 0 +access = 2 +filters = PoolStringArray( "*.mp3", "*.ogg" ) + +[node name="OpenFileDialog" type="FileDialog" parent="."] +margin_left = -696.0 +margin_top = 8.0 +margin_right = -112.0 +margin_bottom = 470.0 +popup_exclusive = true +window_title = "Open a File" +mode = 0 +access = 2 +filters = PoolStringArray( "*.res" ) + +[node name="SaveFileDialog" type="FileDialog" parent="."] +margin_left = -664.0 +margin_top = -24.0 +margin_right = -80.0 +margin_bottom = 438.0 +popup_exclusive = true +window_title = "Save File" +access = 2 +filters = PoolStringArray( "*.res" ) + +[connection signal="connection_from_empty" from="." to="." method="_on_GraphEdit_connection_from_empty"] +[connection signal="connection_request" from="." to="." method="_on_GraphEdit_connection_request"] +[connection signal="connection_to_empty" from="." to="." method="_on_GraphEdit_connection_to_empty"] +[connection signal="copy_nodes_request" from="." to="." method="_on_GraphEdit_copy_nodes_request"] +[connection signal="delete_nodes_request" from="." to="." method="_on_GraphEdit_delete_nodes_request"] +[connection signal="disconnection_request" from="." to="." method="_on_GraphEdit_disconnection_request"] +[connection signal="duplicate_nodes_request" from="." to="." method="_on_GraphEdit_duplicate_nodes_request"] +[connection signal="gui_input" from="." to="." method="_on_Graph_gui_input"] +[connection signal="node_selected" from="." to="." method="_on_Graph_node_selected"] +[connection signal="node_unselected" from="." to="." method="_on_Graph_node_unselected"] +[connection signal="paste_nodes_request" from="." to="." method="_on_GraphEdit_paste_nodes_request"] +[connection signal="pressed" from="HBoxContainer/AddButton" to="." method="_on_AddButton_pressed"] +[connection signal="pressed" from="HBoxContainer/PlayButton" to="." method="_on_PlayButton_pressed"] +[connection signal="pressed" from="HBoxContainer/DebugButton" to="." method="_on_DebugButton_pressed"] +[connection signal="file_selected" from="OpenImgFileDialog" to="." method="_on_OpenImgFileDialog_file_selected"] +[connection signal="popup_hide" from="OpenImgFileDialog" to="." method="_on_OpenImgFileDialog_popup_hide"] +[connection signal="file_selected" from="OpenSndFileDialog" to="." method="_on_OpenSndFileDialog_file_selected"] +[connection signal="popup_hide" from="OpenSndFileDialog" to="." method="_on_OpenSndFileDialog_popup_hide"] +[connection signal="file_selected" from="OpenFileDialog" to="." method="_on_OpenFileDialog_file_selected"] +[connection signal="popup_hide" from="OpenFileDialog" to="." method="_on_OpenFileDialog_popup_hide"] +[connection signal="file_selected" from="SaveFileDialog" to="." method="_on_SaveFileDialog_file_selected"] +[connection signal="popup_hide" from="SaveFileDialog" to="." method="_on_SaveFileDialog_popup_hide"] diff --git a/Scenes/GraphNode.tscn b/Scenes/GraphNode.tscn new file mode 100644 index 0000000..1945872 --- /dev/null +++ b/Scenes/GraphNode.tscn @@ -0,0 +1,132 @@ +[gd_scene load_steps=9 format=2] + +[ext_resource path="res://Scripts/GraphNode.gd" type="Script" id=1] +[ext_resource path="res://Assets/Icons/ImageTexture.svg" type="Texture" id=2] +[ext_resource path="res://Assets/Icons/Reload.svg" type="Texture" id=3] +[ext_resource path="res://Assets/Icons/VisualShaderPort.svg" type="Texture" id=4] +[ext_resource path="res://Assets/Icons/SoundFile.svg" type="Texture" id=5] +[ext_resource path="res://Resources/SelectedFrame.tres" type="StyleBox" id=6] +[ext_resource path="res://Resources/NormalFrame.tres" type="StyleBox" id=7] +[ext_resource path="res://Assets/Icons/Remove.svg" type="Texture" id=8] + +[node name="GraphNode" type="GraphNode"] +margin_right = 232.0 +margin_bottom = 197.0 +rect_min_size = Vector2( 100, 75 ) +custom_colors/resizer_color = Color( 1, 1, 1, 1 ) +custom_icons/port = ExtResource( 4 ) +custom_styles/frame = ExtResource( 7 ) +custom_styles/selectedframe = ExtResource( 6 ) +title = "Title" +show_close = true +resizable = true +slot/0/left_enabled = true +slot/0/left_type = 0 +slot/0/left_color = Color( 0, 0.745098, 0, 1 ) +slot/0/right_enabled = true +slot/0/right_type = 0 +slot/0/right_color = Color( 0, 0.745098, 0, 1 ) +script = ExtResource( 1 ) + +[node name="VBoxContainer" type="VBoxContainer" parent="."] +margin_left = 12.0 +margin_top = 25.0 +margin_right = 281.0 +margin_bottom = 192.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +alignment = 1 + +[node name="Control" type="Control" parent="VBoxContainer"] +margin_right = 269.0 +margin_bottom = 113.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 + +[node name="ColorRect" type="ColorRect" parent="VBoxContainer/Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +color = Color( 0, 0, 0, 1 ) + +[node name="TextureRect" type="TextureRect" parent="VBoxContainer/Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +mouse_filter = 0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +expand = true +stretch_mode = 6 + +[node name="SubtitleEdit" type="TextEdit" parent="VBoxContainer"] +margin_top = 117.0 +margin_right = 269.0 +margin_bottom = 139.0 +rect_min_size = Vector2( 0, 22 ) +hint_tooltip = "Subtitles" +size_flags_horizontal = 3 +wrap_enabled = true + +[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"] +margin_top = 143.0 +margin_right = 269.0 +margin_bottom = 167.0 + +[node name="Label" type="Label" parent="VBoxContainer/HBoxContainer"] +margin_top = 5.0 +margin_right = 63.0 +margin_bottom = 19.0 +text = "Duration: " +valign = 1 + +[node name="SpinBox" type="SpinBox" parent="VBoxContainer/HBoxContainer"] +margin_left = 67.0 +margin_right = 141.0 +margin_bottom = 24.0 +hint_tooltip = "Frame duration (in seconds)" +min_value = 0.1 +max_value = 60.0 +step = 0.1 +page = 0.5 +value = 1.0 +align = 3 +suffix = "s" + +[node name="LoadButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 145.0 +margin_right = 173.0 +margin_bottom = 24.0 +hint_tooltip = "Load image from file" +icon = ExtResource( 2 ) + +[node name="SoundButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 177.0 +margin_right = 205.0 +margin_bottom = 24.0 +hint_tooltip = "Load sound from file" +icon = ExtResource( 5 ) + +[node name="DelSoundButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 209.0 +margin_right = 237.0 +margin_bottom = 24.0 +hint_tooltip = "Remove sound" +icon = ExtResource( 8 ) + +[node name="ReloadButton" type="Button" parent="VBoxContainer/HBoxContainer"] +margin_left = 241.0 +margin_right = 269.0 +margin_bottom = 24.0 +hint_tooltip = "Reload image and sound" +icon = ExtResource( 3 ) +icon_align = 1 + +[connection signal="close_request" from="." to="." method="_on_GraphNode_close_request"] +[connection signal="resize_request" from="." to="." method="_on_GraphNode_resize_request"] +[connection signal="focus_entered" from="VBoxContainer/Control/TextureRect" to="." method="_on_TextureRect_focus_entered"] +[connection signal="gui_input" from="VBoxContainer/Control/TextureRect" to="." method="_on_TextureRect_gui_input"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/LoadButton" to="." method="_on_LoadButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/SoundButton" to="." method="_on_SoundButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/DelSoundButton" to="." method="_on_DelSoundButton_pressed"] +[connection signal="pressed" from="VBoxContainer/HBoxContainer/ReloadButton" to="." method="_on_ReloadButton_pressed"] diff --git a/Scenes/Main.tscn b/Scenes/Main.tscn new file mode 100644 index 0000000..9c88005 --- /dev/null +++ b/Scenes/Main.tscn @@ -0,0 +1,150 @@ +[gd_scene load_steps=4 format=2] + +[ext_resource path="res://Scenes/GraphEdit.tscn" type="PackedScene" id=1] +[ext_resource path="res://Scripts/Main.gd" type="Script" id=3] +[ext_resource path="res://Resources/theme.tres" type="Theme" id=4] + +[node name="Main" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +theme = ExtResource( 4 ) +script = ExtResource( 3 ) + +[node name="Background" type="ColorRect" parent="."] +anchor_right = 1.0 +anchor_bottom = 1.0 +color = Color( 0.121569, 0.121569, 0.113725, 1 ) + +[node name="Graph" parent="." instance=ExtResource( 1 )] +margin_top = 28.0 +rect_min_size = Vector2( 100, 100 ) + +[node name="HBoxContainer" type="HBoxContainer" parent="."] +anchor_right = 1.0 +margin_bottom = 24.0 + +[node name="FileMenuButton" type="MenuButton" parent="HBoxContainer"] +margin_right = 35.0 +margin_bottom = 24.0 +text = "File" +align = 0 + +[node name="EditMenuButton" type="MenuButton" parent="HBoxContainer"] +margin_left = 39.0 +margin_right = 75.0 +margin_bottom = 24.0 +text = "Edit" +align = 0 + +[node name="SelecMenuButton" type="MenuButton" parent="HBoxContainer"] +margin_left = 79.0 +margin_right = 130.0 +margin_bottom = 24.0 +focus_mode = 2 +text = "Select" +align = 0 + +[node name="HelpMenuButton" type="MenuButton" parent="HBoxContainer"] +margin_left = 134.0 +margin_right = 176.0 +margin_bottom = 24.0 +text = "Help" +align = 0 + +[node name="HelpDialog" type="AcceptDialog" parent="."] +visible = true +margin_left = -592.0 +margin_top = 379.0 +margin_right = -41.0 +margin_bottom = 801.0 +popup_exclusive = true +window_title = "Help" + +[node name="Label2" type="RichTextLabel" parent="HelpDialog"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 8.0 +margin_top = 8.0 +margin_right = -8.0 +margin_bottom = -36.0 +bbcode_enabled = true +bbcode_text = "[center][shake rate=10 + level=8][color=white]STORYBOARD MAPPER[/color][/shake] + +[color=aqua]Import images[/color] + [color=silver]Drag & drop images from your file explorer on empty space. If you are dragging multiple files at once, pay attention to the file your mouse cursor is on when dragging, this will be the first node of the sequence.[/color] + [color=silver]Tip: Set the number of columns (in the upper right corner) before dragging the files.[/color] + +[color=aqua]Add a new node[/color] + [color=silver]Click on the + button, or double-click on empty space, or start dragging from a node's input or output pin, then release on empty space.[/color] + +[color=aqua]Connect two nodes[/color] + [color=silver]Drag from the first node's output pin to the second node's input pin (or vice-versa).[/color] + +[color=aqua]Disconnect two nodes[/color] + [color=silver]Drag the connection's end (the second node's input pin), then release on empty space.[/color] + +[color=aqua]Play sequence[/color] + [color=silver]Select the first node of the sequence, then click on the play button, or double-click on the first node of the sequence.[/color] +[/center]" +text = "STORYBOARD MAPPER + +Import images + Drag & drop images from your file explorer on empty space. If you are dragging multiple files at once, pay attention to the file your mouse cursor is on when dragging, this will be the first node of the sequence. + Tip: Set the number of columns (in the upper right corner) before dragging the files. + +Add a new node + Click on the + button, or double-click on empty space, or start dragging from a node's input or output pin, then release on empty space. + +Connect two nodes + Drag from the first node's output pin to the second node's input pin (or vice-versa). + +Disconnect two nodes + Drag the connection's end (the second node's input pin), then release on empty space. + +Play sequence + Select the first node of the sequence, then click on the play button, or double-click on the first node of the sequence. +" + +[node name="AboutDialog" type="AcceptDialog" parent="."] +visible = true +margin_left = -593.0 +margin_top = -82.0 +margin_right = -44.0 +margin_bottom = 294.0 +popup_exclusive = true +window_title = "About" + +[node name="Label2" type="RichTextLabel" parent="AboutDialog"] +anchor_right = 1.0 +anchor_bottom = 1.0 +margin_left = 8.0 +margin_top = 8.0 +margin_right = -8.0 +margin_bottom = -36.0 +size_flags_horizontal = 3 +size_flags_vertical = 3 +bbcode_enabled = true +bbcode_text = "[center][shake rate=10 level=8][color=white]STORYBOARD MAPPER v0.1[/color][/shake] + +Copyright (c) 2022 Jean-Yves Chasle[/center] + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." +text = "STORYBOARD MAPPER v0.1 + +Copyright (c) 2022 Jean-Yves Chasle + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." + +[connection signal="about_to_show" from="HBoxContainer/EditMenuButton" to="." method="_on_EditMenuButton_about_to_show"] +[connection signal="about_to_show" from="HBoxContainer/SelecMenuButton" to="." method="_on_SelecMenuButton_about_to_show"] +[connection signal="popup_hide" from="HelpDialog" to="." method="_on_HelpDialog_popup_hide"] +[connection signal="popup_hide" from="AboutDialog" to="." method="_on_AboutDialog_popup_hide"] diff --git a/Scripts/AsyncImageLoader.gd b/Scripts/AsyncImageLoader.gd new file mode 100644 index 0000000..9ffedc6 --- /dev/null +++ b/Scripts/AsyncImageLoader.gd @@ -0,0 +1,220 @@ +extends Node + +var _exit_mutex: Mutex +var _load_queue_mutex: Mutex +var _purge_queue_mutex: Mutex +var _cache_mutex: Mutex +var _load_semaphore: Semaphore +var _purge_semaphore: Semaphore +var _load_thread: Thread +var _purge_thread: Thread + +var _exit_thread: bool +var _load_queue: Array # [String] +var _purge_queue: Array # [String] +var _cache: Dictionary # {String : Image} + + +func _ready(): + _exit_thread = false + _load_queue = [] + _purge_queue = [] + _cache = {} + _exit_mutex = Mutex.new() + _load_queue_mutex = Mutex.new() + _purge_queue_mutex = Mutex.new() + _cache_mutex = Mutex.new() + _load_semaphore = Semaphore.new() + _purge_semaphore = Semaphore.new() + _load_thread = Thread.new() + _purge_thread = Thread.new() + var err = _load_thread.start(self, "_load_thread_loop", null, Thread.PRIORITY_NORMAL) + if err != OK: + print("Error ", err, " starting _load_thread") + err = _purge_thread.start(self, "_purge_thread_loop", null, Thread.PRIORITY_NORMAL) + if err != OK: + print("Error ", err, " starting _purge_thread") + + +# This function is executed on the main thread. +func load_image_async(path: String, priority: bool = false): + assert(path) + print("Queueing for loading ", path) + + # Return immediately if the path is already in _purge_queue_mutex. + _purge_queue_mutex.lock() + if _purge_queue.has(path): + _purge_queue_mutex.unlock() + return + _purge_queue_mutex.unlock() + + # Returns immediately if the image is already pending or loaded. + if _threadsafe_is_path_in_cache(path): + return + + _load_queue_mutex.lock() + if _load_queue.has(path): + # Return immediately if the path is already in the queue. + _load_queue_mutex.unlock() + return + else: + # Queue the path. + if priority: + _load_queue.push_front(path) + else: + _load_queue.push_back(path) + _load_queue_mutex.unlock() + + # Unlock _thread_loop(). + _load_semaphore.post() + + +# This function is executed on the main thread. +func purge_image_async(path: String): + assert(path) + print("Queueing for purging ", path) + + # Retire path de _load_queue s'il s'y trouve. + _load_queue_mutex.lock() + if _load_queue.has(path): + _load_queue.erase(path) + _load_queue_mutex.lock() + + # L'image est peut-être en train d'être chargée. Dans ce cas, _purge_queue_mutex est locked dans _load_thread_loop. + _purge_queue_mutex.lock() + if _purge_queue.has(path): + # Return immediately if the path is already in the queue. + _purge_queue_mutex.unlock() + return + else: + # Queue the path. + _purge_queue.push_back(path) + _purge_queue_mutex.unlock() + + # Unlock _thread_loop(). + _purge_semaphore.post() + + +# This function is executed on the main thread. +func fetch_image(path: String) -> Image: + return _threadsafe_get_image_from_cache(path) + + +func _load_thread_loop(_unused): + print("_load_thread_loop running...") + while true: + _load_semaphore.wait() # Wait until posted. + + if _threadsafe_check_exit_condition(): + break + + # Bloque purge_image_async pendant le chargement de l'image, pour que purge_image_async puisse l'inscrire au déchargement juste après. + _purge_queue_mutex.lock() + + var path: = _threadsafe_get_next_load_task() + assert(path) + + _cache_mutex.lock() + _cache[path] = null # Pending + _cache_mutex.unlock() + + var img: = _threadsafe_load_image(path) + assert(img) + + _cache_mutex.lock() + _cache[path] = img # Loaded + _cache_mutex.unlock() + + _purge_queue_mutex.unlock() + + print("Loaded ", path) + + +func _purge_thread_loop(_unused): + print("_purge_thread_loop running...") + while true: + _purge_semaphore.wait() # Wait until posted. + + if _threadsafe_check_exit_condition(): + break + + var path: = _threadsafe_get_next_purge_task() + assert(path) + + _threadsafe_cancel_loading(path) + + _cache_mutex.lock() + if _cache.has(path): + _cache.erase(path) + _cache_mutex.unlock() + + print("Purged ", path) + + +func _threadsafe_check_exit_condition() -> bool: + _exit_mutex.lock() + var exit_thread: bool = _exit_thread + _exit_mutex.unlock() + return exit_thread + + +# This function is executed on the thread loop. +func _threadsafe_load_image(path: String) -> Image: +# texture_rect.texture = load(path) + var img = Image.new() + var err = img.load(path) + if err != OK: + print("Error loading image ", path, " : ", err) + return null + return img + + +func _threadsafe_get_next_load_task() -> String: + _load_queue_mutex.lock() + var path: String = _load_queue.pop_front() + _load_queue_mutex.unlock() + return path + + +func _threadsafe_cancel_loading(path: String): + _load_queue_mutex.lock() + if _load_queue.has(path): + _load_queue.erase(path) + _load_queue_mutex.unlock() + + +func _threadsafe_get_next_purge_task() -> String: + _purge_queue_mutex.lock() + var path: String = _purge_queue.pop_front() + _purge_queue_mutex.unlock() + return path + + +func _threadsafe_is_path_in_cache(path: String) -> bool: + _cache_mutex.lock() + var cached: bool = _cache.has(path) + _cache_mutex.unlock() + return cached + + +func _threadsafe_get_image_from_cache(path: String) -> Image: + _cache_mutex.lock() + var cached: bool = _cache.has(path) + if !cached: + _cache_mutex.unlock() + return null + var img: Image = _cache[path] + _cache_mutex.unlock() + return img + + +func _exit_tree(): + _exit_mutex.lock() + _exit_thread = true + _exit_mutex.unlock() + _load_semaphore.post() + _purge_semaphore.post() + _load_thread.wait_to_finish() + _purge_thread.wait_to_finish() + _load_thread = null + _purge_thread = null diff --git a/Scripts/DisplayDialog.gd b/Scripts/DisplayDialog.gd new file mode 100644 index 0000000..7122294 --- /dev/null +++ b/Scripts/DisplayDialog.gd @@ -0,0 +1,278 @@ +extends WindowDialog +class_name DisplayDialog + + +enum { + PLAYING, + STOPPED, +} + +var window_bounds: = Rect2() +var node_chain: Array = [] +var node_chain_index: int = -1 +var state: int = STOPPED +var is_looping = false + +onready var graph_node = preload("res://Scenes/GraphNode.tscn") +onready var display_rect: = $VBoxContainer/Control/TextureRect +onready var subtitle: = $VBoxContainer/Control/Subtitle +onready var subedit: = $VBoxContainer/HBoxContainer/SubtitleEdit +onready var spinbox: = $VBoxContainer/HBoxContainer/SpinBox +onready var play_timer: = $PlayTimer +onready var audio_player: = $AudioStreamPlayer + + +func _ready(): + assert(graph_node) + assert(display_rect) + assert(subtitle) + assert(subedit) + assert(play_timer) + assert(audio_player) + move_popup_out_of_the_way() + + +func init_dialog(first: ImageGraphNode): + assert(first) + state = STOPPED + update_node_chain(first) + + +# Hack to prevent hidden popups from stealing mouse input. +func move_popup_out_of_the_way(): + var infinite_pos: = Vector2(-1e6, -1e6) + rect_position = infinite_pos + + +#func load_image_async(index: int): +# assert(index >= 0) +# assert(index < node_chain.size()) +# var node: ImageGraphNode = node_chain[index] +# assert(node) +# var img_loader: AsyncImageLoader = AsyncImageLoader +# assert(img_loader) +# img_loader.load_image_async(node.img_path) +# +# +#func purge_image_async(index: int): +# assert(index >= 0) +# assert(index < node_chain.size()) +# var node: ImageGraphNode = node_chain[index] +# assert(node) +# var img_loader: AsyncImageLoader = AsyncImageLoader +# assert(img_loader) +# img_loader.purge_image_from_cache(node.img_path) +# +# +#func update_image_cache(index: int): +# # Unloads 3 frames starting from index. +# var min_index = max(index - 1, 0) +# for i in range(min_index, index): +# purge_image_async(index) +# +# # Loads 3 frames starting from index. +# var max_index = min(index + 3, node_chain.size()) +# for i in range(index, max_index): +# load_image_async(i) + + +func _on_DisplayDialog_about_to_show(): + assert(node_chain.size()) + #display_node(0) + play_animation_from_start() + + +func _on_DisplayDialog_popup_hide(): + stop_animation() + window_bounds.position = rect_position + window_bounds.size = rect_size + move_popup_out_of_the_way() + + +func _on_PlayButton_pressed(): + toggle_pause_resume_animation() + + +func _on_TextureRect_gui_input(event): + if event is InputEventMouseButton and event.pressed: + toggle_pause_resume_animation() + + +func _on_StopButton_pressed(): + stop_animation() + + +func _on_FirstButton_pressed(): + pause_animation() + display_node(0, false) + + +func _on_LastButton_pressed(): + pause_animation() + display_node(node_chain.size() - 1, false) + + +func _on_PrevButton_pressed(): + pause_animation() + if node_chain_index > 0: + display_node(node_chain_index - 1, false) + + +func _on_NextButton_pressed(): + pause_animation() + if node_chain_index < node_chain.size() - 1: + display_node(node_chain_index + 1, false) + + +func _on_LoopButton_toggled(button_pressed: bool): + is_looping = button_pressed + + +func _on_PlayTimer_timeout(): + assert(state == PLAYING) + assert(node_chain_index >= 0) + + # Joue le prochain node de la chaine si possible. + if node_chain_index < node_chain.size() - 1: + play_node(node_chain_index + 1) + return + + # On est arrivé à la fin, recommencer ? + if is_looping: + play_animation_from_start() + else: + stop_animation() + + +func update_node_chain(first: ImageGraphNode): + assert(first) + node_chain_index = -1 + node_chain.clear() + var node: = first + while node != null: + node_chain.push_back(node) + node = node.next_node + + +func play_animation_from_start(): + play_node(0) + + +func toggle_pause_resume_animation(): + assert(node_chain.size()) + match state: + PLAYING: + pause_animation() + STOPPED: + resume_animation() + + +func pause_animation(): + state = STOPPED + spinbox.editable = true + if not play_timer.is_stopped(): + play_timer.stop() + + +func resume_animation(): + play_node(node_chain_index) + + +func stop_animation(): + pause_animation() + #display_node(0) + + +func play_node(index: int): + state = PLAYING + spinbox.editable = false + display_node(index, true) + var node: ImageGraphNode = node_chain[index] + play_timer.start(node.get_duration()) + + +func refresh(): + assert(node_chain.size()) + assert(node_chain_index >= 0) + assert(node_chain_index < node_chain.size()) + display_node(node_chain_index, false) + + +func display_node(index: int, play_sound: bool): + assert(index >= 0) + assert(index < node_chain.size()) + assert(display_rect) + node_chain_index = index + var node: ImageGraphNode = node_chain[index] + + var tex = load_image_from_file(node.img_path) + display_rect.texture = tex if tex else node.get_thumbnail_texture() + + if audio_player.is_playing(): + audio_player.stop() + if play_sound and node.sound: + audio_player.stream = node.sound + audio_player.play() + + update_window_title(node.img_path) + + subtitle.text = node.get_subtitle() + subedit.text = node.get_subtitle() + + spinbox.set_value(node.get_duration()) + + +func load_image_from_file(path: String) -> ImageTexture: + var img = Image.new() + var err = img.load(path) + if err != OK: + print("Error loading image ", path, " : ", err) + return null + var tex = ImageTexture.new() + tex.create_from_image(img) + return tex + + +func update_window_title(path: String): + var file_name = path.get_file() + file_name = file_name.rstrip('.' + file_name.get_extension()) + set_title(file_name) + + +func _on_SubtitleEdit_text_changed(): + var node: ImageGraphNode = node_chain[node_chain_index] + assert(node) + subtitle.text = subedit.text + node.subedit.text = subedit.text + + +func _on_SpinBox_value_changed(value): + var node: ImageGraphNode = node_chain[node_chain_index] + assert(node) + if value != node.get_duration(): + assert(state == STOPPED) + node.spinbox.set_value(value) + + +func _on_LoadButton_pressed(): + var node: ImageGraphNode = node_chain[node_chain_index] + assert(node) + node.open_image_file() + + +func _on_SoundButton_pressed(): + var node: ImageGraphNode = node_chain[node_chain_index] + assert(node) + node.open_sound_file() + + +func _on_ReloadButton_pressed(): + var node: ImageGraphNode = node_chain[node_chain_index] + assert(node) + node.reload_image_file() + + +func _on_DelSoundButton_pressed(): + var node: ImageGraphNode = node_chain[node_chain_index] + assert(node) + node.remove_sound() diff --git a/Scripts/GraphData.gd b/Scripts/GraphData.gd new file mode 100644 index 0000000..e2461a1 --- /dev/null +++ b/Scripts/GraphData.gd @@ -0,0 +1,6 @@ +extends Resource +class_name GraphData + +export var version: float +export var nodes: Array +export var connections: Array diff --git a/Scripts/GraphEdit.gd b/Scripts/GraphEdit.gd new file mode 100644 index 0000000..988a833 --- /dev/null +++ b/Scripts/GraphEdit.gd @@ -0,0 +1,923 @@ +extends GraphEdit +class_name ImageGraph + +#export(NodePath) var popup + +const APP_NAME: String = "Storyboard Mapper" +const DEFAULT_FILENAME: String = "Untitled" +const FILE_VERSION: float = 0.1 +const IMG_EXTENSIONS: Array = ["jpg", "jpeg", "png", "bmp"] +const DEFAULT_NODE_SPACING: float = 40.0 +const MIN_DRAG_DISTANCE: float = 5.0 + +var custom_node_size: Vector2 +var current_path: String +var current_file_name: String +var selected_nodes: Array = [] +var copied_nodes: Array = [] +var active_node: ImageGraphNode = null + +var dragging_selected_nodes: bool = false +var dragged_nodes_initial_offsets_in_graph_space: Array = [] +var old_global_mouse_position: Vector2 +var nodes_were_dragged: bool = false + +onready var graph_node = preload("res://Scenes/GraphNode.tscn") +onready var display_dlg: = $DisplayDialog +onready var image_dlg: = $OpenImgFileDialog +onready var sound_dlg: = $OpenSndFileDialog +onready var open_dlg: = $OpenFileDialog +onready var save_dlg: = $SaveFileDialog +onready var add_button: = $HBoxContainer/AddButton +onready var play_button: = $HBoxContainer/PlayButton +onready var grid_num_cols: = $HBoxContainer/GridColsSpinBox + + +func _ready(): + OS.set_low_processor_usage_mode(true) # Economise la batterie des mobiles. + current_file_name = DEFAULT_FILENAME + current_path = "" + update_main_window_title() + get_tree().connect("files_dropped", self, "_on_files_dropped") + move_popups_out_of_the_way() + + +func _process(_delta): + # Are we dragging selected nodes? + if dragging_selected_nodes: + var global_mouse_position = get_global_mouse_position() + + # Considère dragging si ça n'était pas déjà le cas et que la distance de dragging est suffisante. + if !nodes_were_dragged and global_mouse_position.distance_to(old_global_mouse_position) >= MIN_DRAG_DISTANCE: + nodes_were_dragged = true + + if nodes_were_dragged: + for i in range(selected_nodes.size()): + selected_nodes[i].set_offset(get_mouse_position_in_graph_space() - dragged_nodes_initial_offsets_in_graph_space[i]) + + +########## +## EDIT ## +########## + +func _on_DebugButton_pressed(): + print("-----------------------------") + print("Selected: ", selected_nodes) + print("Copied: ", copied_nodes) +# print("DisplayDialog: ", display_dlg.rect_position) +# print("ImgFileDlg: ", image_dlg.rect_position) +# print("OpenFileDialog: ", open_dlg.rect_position) +# print("SaveFileDialog: ", save_dlg.rect_position) +# var img_loader: AsyncImageLoader = AsyncImageLoader +# assert(img_loader) +# var images: = [ +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht020_Prt50_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht020_Prt50_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht020_Prt50_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht020_Prt51_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht020_Prt52_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht021_Prt01_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht021_Prt02_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht021_Prt03_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht021_Prt04_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht022_Prt01_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht022_Prt02_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht022_Prt03_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht023_Prt01_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht024_Prt01_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht024_Prt02_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht024_Prt03_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht025_Prt01_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht025_Prt02_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht025_Prt03_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht026_Prt01_Ver01.png", +# "G:/COMMON/DATA/JycGimpProjects/Storyboards/Export/DrumsOfTumbalku_Seq001_Sht026_Prt02_Ver01.png", +# ] +# for path in images: +# img_loader.load_image_async(path) +# yield(get_tree().create_timer(0.05), "timeout") +# yield(get_tree().create_timer(0.2), "timeout") +# for path in images: +# var img: = img_loader.fetch_image(path) +# print("img: ", str(img)) + + +func update_main_window_title(): + OS.set_window_title(current_file_name + " - " + APP_NAME) + + +func update_buttons(): + play_button.disabled = selected_nodes.size() != 1 + + +# Hack to prevent hidden popups from stealing mouse input. +func move_popups_out_of_the_way(): + var infinite_pos: = Vector2(-1e6, -1e6) +# if not display_dlg.visible: +# display_dlg.rect_position = infinite_pos + if not image_dlg.visible: + image_dlg.rect_position = infinite_pos + if not sound_dlg.visible: + sound_dlg.rect_position = infinite_pos + if not open_dlg.visible: + open_dlg.rect_position = infinite_pos + if not save_dlg.visible: + save_dlg.rect_position = infinite_pos +# var parent = get_parent() +# assert(parent) +# if parent.has_method("move_popups_out_of_the_way"): +# parent.move_popups_out_of_the_way() + + +func _on_OpenImgFileDialog_popup_hide(): + move_popups_out_of_the_way() + + +func _on_OpenSndFileDialog_popup_hide(): + move_popups_out_of_the_way() + + +func _on_SaveFileDialog_popup_hide(): + move_popups_out_of_the_way() + + +func _on_OpenFileDialog_popup_hide(): + move_popups_out_of_the_way() + + +func get_grid_num_cols() -> int: + return grid_num_cols.get_value() + + +func start_dragging_selected_nodes(pointed_node: ImageGraphNode): + dragging_selected_nodes = true + nodes_were_dragged = false + dragged_nodes_initial_offsets_in_graph_space.clear() # Security + var global_mouse_position = get_global_mouse_position() + old_global_mouse_position = global_mouse_position + for node in selected_nodes: + var ofs: Vector2 = (global_mouse_position - rect_position - node.rect_position) / zoom + if is_using_snap(): + ofs = snap_position(ofs) + dragged_nodes_initial_offsets_in_graph_space.push_back(ofs) + + +func stop_dragging_selected_nodes() -> bool: + dragging_selected_nodes = false + dragged_nodes_initial_offsets_in_graph_space.clear() + return nodes_were_dragged + + +func align_horizontally(): + if selected_nodes.size() < 2: + return + var master_node: ImageGraphNode = selected_nodes.front() + var master_node_x: = master_node.offset.x + for node in selected_nodes: + node.offset.x = master_node_x + + +func align_vertically(): + if selected_nodes.size() < 2: + return + var master_node: ImageGraphNode = selected_nodes.front() + var master_node_y: = master_node.offset.y + for node in selected_nodes: + node.offset.y = master_node_y + + +func distribute_row(): + if selected_nodes.size() != 1: + return + var node: ImageGraphNode = selected_nodes.front() + var ofs: Vector2 = node.offset + while node.next_node: + ofs.x += node.rect_size.x + DEFAULT_NODE_SPACING + node = node.next_node + node.offset = ofs + + +func distribute_col(): + if selected_nodes.size() != 1: + return + var node: ImageGraphNode = selected_nodes.front() + var ofs: Vector2 = node.offset + while node.next_node: + ofs.y += node.rect_size.y + DEFAULT_NODE_SPACING + node = node.next_node + node.offset = ofs + + +func distribute_diag(): + if selected_nodes.size() != 1: + return + var node: ImageGraphNode = selected_nodes.front() + var ofs: Vector2 = node.offset + while node.next_node: + ofs.x += node.rect_size.x + DEFAULT_NODE_SPACING + ofs.y += node.rect_size.y / 2 + DEFAULT_NODE_SPACING + node = node.next_node + node.offset = ofs + + +# Drag and drop de fichiers. +func distribute_grid(): + if selected_nodes.size() != 1: + return + var num_cols: int = get_grid_num_cols() + var node: ImageGraphNode = selected_nodes.front() + var ofs: Vector2 = node.offset + var line_start: = ofs.x + var col = 0 + while node.next_node: + col += 1 + if col < num_cols: + ofs.x += node.rect_size.x + DEFAULT_NODE_SPACING + else: + col = 0 + ofs.x = line_start + ofs.y += node.rect_size.y + DEFAULT_NODE_SPACING + node = node.next_node + node.offset = ofs + + +func set_custom_size_from_selected_node(): + if selected_nodes.size() != 1: + return + var node = selected_nodes.front() + custom_node_size = node.rect_size + + +func set_selected_nodes_to_custom_size(): + if selected_nodes.size() == 0: + return + for node in selected_nodes: + node.rect_size = custom_node_size + + +######### +## NEW ## +######### + +func snap_position(pos: Vector2) -> Vector2: + var snap = get_snap() + pos.x = int(pos.x / snap) * snap + pos.y = int(pos.y / snap) * snap + return pos + + +# Convertit un offset dans le viewport (ex: get_global_mouse_position()) dans l'espace du graph. +func convert_viewport_ofs_to_graph_ofs(viewport_pos: Vector2) -> Vector2: + var ofs = (scroll_offset + viewport_pos) / zoom + if !is_using_snap(): + return ofs + return snap_position(ofs) + + +# Inverse de la conversion ci-dessus. +func convert_graph_ofs_to_viewport_ofs(graph_pos: Vector2) -> Vector2: + var ofs = graph_pos * zoom - scroll_offset + return ofs + + +func get_mouse_position_in_graph_space() -> Vector2: + return convert_viewport_ofs_to_graph_ofs(get_global_mouse_position() - rect_position) + + +# Ajoute un nouveau node au graph. Son centre est positionné à l'offset donné. +func add_new_node(ofs: Vector2, select_exclusive: bool = true, autoload: bool = true) -> ImageGraphNode: + var new_node = graph_node.instance() + add_child(new_node, true) + new_node.set_offset(ofs - new_node.rect_size / 2) + if select_exclusive: + select_node_ex(new_node) + else: + #new_node.selected = true + select_node_ex(new_node, false) + if autoload: + open_load_image_dialog(new_node) + return new_node + + +# Ajoute un nouveau node au graph quand l'utilisateur appuie sur le bouton 'Add'. +func _on_AddButton_pressed(): + add_new_node(get_mouse_position_in_graph_space() + Vector2(200, 200)) + + +# Ajoute un nouveau node au graph quand l'utilisateur double-clique sur le graph. +func _on_Graph_gui_input(event): + if event is InputEventMouseButton and event.doubleclick: + add_new_node(get_mouse_position_in_graph_space()) + + +# Drag and drop de fichiers. +func _on_files_dropped(files, screen): + yield(get_tree(),"idle_frame") # hack to get valid mouse position + deselect_all_nodes() + var ofs: = get_mouse_position_in_graph_space() + var line_start: = ofs.x + var num_cols: int = get_grid_num_cols() + var col = 0 + var prev_node: ImageGraphNode = null + for path in files: + var ext: String = path.get_extension() + if IMG_EXTENSIONS.has(ext): + var new_node: ImageGraphNode = add_new_node(ofs, false, false) + new_node.load_thumbnail_from_file(path) + + col += 1 + if col < num_cols: + ofs.x += new_node.rect_size.x + DEFAULT_NODE_SPACING + else: + col = 0 + ofs.x = line_start + ofs.y += new_node.rect_size.y + DEFAULT_NODE_SPACING + + if prev_node: + # Crée une nouvelle connexion entre les nodes 'prev_node' et 'new_node'. + var err = connect_node(prev_node.name, 0, new_node.name, 0) + if err == OK: + prev_node.next_node = new_node + else: + print(err) + prev_node = new_node + + +########## +## FIND ## +########## + +# Recursive +func _find_all_nodes_before_node(node: ImageGraphNode, connections: Dictionary, found_nodes: Array): + assert(node) + if not connections.has(node): + return + var prev_nodes: Array = connections[node] + for n in prev_nodes: + if found_nodes.has(n): + continue + found_nodes.push_back(n) + _find_all_nodes_before_node(n, connections, found_nodes) + + +func _find_all_nodes_before_selected(connections: Dictionary, found_nodes: Array): + for node in selected_nodes: + _find_all_nodes_before_node(node, connections, found_nodes) + + +func _find_all_nodes_after_node(node: ImageGraphNode, found_nodes: Array): + assert(node) + while node.next_node: + node = node.next_node + if found_nodes.has(node): + break + found_nodes.push_back(node) + + +func _find_all_nodes_after_selected(found_nodes: Array): + for node in selected_nodes: + _find_all_nodes_after_node(node, found_nodes) + + +func _find_terminating_node(node: ImageGraphNode) -> ImageGraphNode: + assert(node) + while node.next_node: + node = node.next_node + return node # last node + + +############ +## SELECT ## +############ + +func get_num_selected_nodes(): + return selected_nodes.size() + + +func get_num_copied_nodes(): + return copied_nodes.size() + + +# Sélectionne seulement le node donné du graph. +func select_node_ex(node: ImageGraphNode, exclusive: bool = true): + assert(node) + #print("select_node_ex, ", exclusive) + if exclusive: + deselect_all_nodes() + if not node.selected: + node.set_selected(true) # /!\ N'émet pas de signal. + if not selected_nodes.has(node): + selected_nodes.push_back(node) + update_buttons() + + +func select_all_nodes(): + selected_nodes.clear() + for node in get_children(): + if node is ImageGraphNode:# and not node.is_selected(): + node.set_selected(true) # /!\ N'émet pas de signal. + selected_nodes.push_back(node) + update_buttons() + + +# Désélectionne le node donné. +func deselect_node(node: ImageGraphNode): + #print("deselect_node") + assert(node) + if node.selected: + node.set_selected(false) # /!\ N'émet pas de signal. + if selected_nodes.has(node): + selected_nodes.erase(node) + update_buttons() + + +# Désélectionne tous les nodes du graph. +func deselect_all_nodes(): + #print("deselect_all_nodes") + for node in get_children(): + if node is ImageGraphNode and node.is_selected(): + node.set_selected(false) # /!\ N'émet pas de signal. + selected_nodes.clear() + update_buttons() + + +func select_all_nodes_before_selected_nodes(): + if selected_nodes.size() == 0: + return + var connections: = _get_connection_info() + var found_nodes: = [] + _find_all_nodes_before_selected(connections, found_nodes) + for node in found_nodes: + select_node_ex(node, false) + update_buttons() + + +func select_all_nodes_after_selected_nodes(): + if selected_nodes.size() == 0: + return + var found_nodes: = [] + _find_all_nodes_after_selected(found_nodes) + for node in found_nodes: + select_node_ex(node, false) + update_buttons() + + +func select_all_nodes_flowing_through_selected_nodes(): + if selected_nodes.size() == 0: + return + var connections: = _get_connection_info() + var found_nodes: = [] + _find_all_nodes_before_selected(connections, found_nodes) + _find_all_nodes_after_selected(found_nodes) + for node in found_nodes: + select_node_ex(node, false) + update_buttons() + + +func select_all_interconnected_nodes_with_selected_nodes(): + if selected_nodes.size() == 0: + return + # Find all terminating nodes from selection. + var terminators: = [] + for node in selected_nodes: + var last: = _find_terminating_node(node) + if not terminators.has(last): + terminators.push_back(last) + + var connections: = _get_connection_info() + var found_nodes: = terminators.duplicate() # Terminators have to be selected too. + for node in terminators: + _find_all_nodes_before_node(node, connections, found_nodes) + for node in found_nodes: + select_node_ex(node, false) + update_buttons() + + +func _on_Graph_node_selected(node: ImageGraphNode): + #print("_on_Graph_node_selected") + if not selected_nodes.has(node): + selected_nodes.push_back(node) + update_buttons() + + +func _on_Graph_node_unselected(node: ImageGraphNode): + #print("_on_Graph_node_unselected") + if selected_nodes.has(node): + selected_nodes.erase(node) + update_buttons() + + +############# +## CONNECT ## +############# + +func _get_connection_info() -> Dictionary: + var connections: = {} + for c in get_connection_list(): + var from_node: ImageGraphNode = get_node(c.from) + var to_node: ImageGraphNode = get_node(c.to) + assert(from_node) + assert(to_node) + assert(from_node.next_node == to_node) + if connections.has(to_node): + connections[to_node].push_back(from_node) + else: + connections[to_node] = [from_node] # new array + return connections + + +# Supprime toutes les connexions entrantes du node donné. +func remove_node_input_connections(node: ImageGraphNode): + assert(node) + for connection in get_connection_list(): + if connection.to == node.name: + disconnect_node(connection.from, connection.from_port, connection.to, connection.to_port) + var from_node: ImageGraphNode = get_node(connection.from) + assert(from_node) + from_node.next_node = null + + +# Supprime la connexion sortante du node donné. +func remove_node_output_connection(node: ImageGraphNode): + assert(node) + if node.next_node: + disconnect_node(node.name, 0, node.next_node.name, 0) + node.next_node = null + + +# Supprime toutes les connexions entrantes et sortantes du node donné. +func remove_node_connections(node: ImageGraphNode): + assert(node) + remove_node_input_connections(node) + remove_node_output_connection(node) + + +# Crée une nouvelle connexion entre les nodes de noms donnés 'from' et 'to'. +func _on_GraphEdit_connection_request(from: String, from_slot: int, to: String, to_slot: int): + # Récupère les nodes 'from' et 'to' d'après les noms donnés. + var from_node: ImageGraphNode = get_node(from) + var to_node: ImageGraphNode = get_node(to) + assert(from_node) + assert(to_node) + + # Refuse la nouvelle connexion si le node se connecte à lui-même. + if from == to: + return + + # Refuse la nouvelle connexion si elle existe déjà. + if from_node.next_node == to_node: + return + + # Crée une nouvelle connexion entre les nodes 'from' et 'to'. + var err = connect_node(from, from_slot, to, to_slot) + if err != OK: + print(err) + + # Supprime l'ancienne connexion si elle existe. + if from_node.next_node != null: + disconnect_node(from, from_slot, from_node.next_node.name, from_node.next_node_slot) + + # Assigne le node 'from' comme node suivant du node 'to'. + from_node.next_node = get_node(to) + + +# Crée un nouveau node si l'utilisateur traîne et relâche sur le graph une nouvelle connexion sortante depuis un node existant. +func _on_GraphEdit_connection_to_empty(from: String, from_slot: int, release_position: Vector2): + # Récupère le node 'from' d'après le nom donné. + var from_node: ImageGraphNode = get_node(from) + assert(from_node) + + # Crée un nouveau node et le connecte. + var new_node = add_new_node(convert_viewport_ofs_to_graph_ofs(release_position)) + assert(new_node) + connect_node(from, from_slot, new_node.name, from_slot) + + # Supprime l'ancienne connexion si elle existe. + if from_node.next_node != null: + disconnect_node(from, from_slot, from_node.next_node.name, from_node.next_node_slot) + + # Assigne le nouveau node comme node suivant du node 'from'. + from_node.next_node = new_node + + +# Crée un nouveau node si l'utilisateur traîne et relâche sur le graph une nouvelle connexion entrante depuis un node existant. +func _on_GraphEdit_connection_from_empty(to: String, to_slot: int, release_position: Vector2): + # Récupère le node 'to' d'après le nom donné. + var to_node: ImageGraphNode = get_node(to) + assert(to_node) + + # Crée un nouveau node et le connecte. + var new_node: ImageGraphNode = add_new_node(convert_viewport_ofs_to_graph_ofs(release_position)) + assert(new_node) + connect_node(new_node.name, to_slot, to, to_slot) + + # Assigne le node 'to' comme node suivant du nouveau node. + new_node.next_node = to_node + + +func _on_GraphEdit_disconnection_request(from: String, from_slot: int, to: String, to_slot: int): + # Récupère le node from d'après le nom donné. + var from_node: ImageGraphNode = get_node(from) + assert(from_node) + + # Déconnecte le node 'from' du node 'to'. + disconnect_node(from, from_slot, to, to_slot) + + # Assigne null comme node suivant du node 'from'. + from_node.next_node = null + + +############### +## DUPLICATE ## +############### + +func duplicate_node(node: ImageGraphNode, ofs: Vector2) -> ImageGraphNode: + var new_node: ImageGraphNode = node.duplicate() + if new_node.resizable: + new_node.rect_size = node.rect_size + new_node.set_offset(ofs - node.rect_size / 2) + new_node.img_path = node.img_path + add_child(new_node, true) + return new_node + + +func connect_duplicated_nodes(old_to_new: Dictionary): + for old_node in old_to_new: + if old_node.next_node and old_to_new.has(old_node.next_node): + var node = old_to_new[old_node] + var next_node = old_to_new[old_node.next_node] + var err = connect_node(node.name, 0, next_node.name, 0) + if err != OK: + print(err) + node.next_node = next_node + + +func _on_GraphEdit_copy_nodes_request(): + copied_nodes.clear() + for node in get_children(): + if node is ImageGraphNode and node.is_selected(): + copied_nodes.append(node) + print("[cop] selected_nodes = ", selected_nodes) + print("[cop] copied_nodes = ", copied_nodes) + + +func get_group_center(nodes: Array) -> Vector2: + assert(nodes) + assert(nodes.size()) + var sum: = Vector2.ZERO + for node in nodes: + sum += node.rect_position + return sum / nodes.size() + + +func _on_GraphEdit_paste_nodes_request(): + print("[paste] selected_nodes = ", selected_nodes) + print("[paste] copied_nodes = ", copied_nodes) + if copied_nodes.empty(): + return + var old_group_center: = get_group_center(copied_nodes) + var old_to_new: = {} + deselect_all_nodes() + var new_group_center: Vector2 = get_global_mouse_position() - rect_position + for old_node in copied_nodes: + var new_node = duplicate_node(old_node, convert_viewport_ofs_to_graph_ofs(new_group_center + old_node.rect_position - old_group_center)) + select_node_ex(new_node, false) + old_to_new[old_node] = new_node + + # Connecte les nouveaux nodes comme les anciens. + connect_duplicated_nodes(old_to_new) + + +func _on_GraphEdit_duplicate_nodes_request(): + if selected_nodes.empty(): + return + var old_group_center: = get_group_center(selected_nodes) + var old_to_new: = {} + var old_nodes = selected_nodes.duplicate() + #deselect_all_nodes() + var new_group_center: Vector2 = get_global_mouse_position() - rect_position + for old_node in old_nodes: + deselect_node(old_node) + var new_node = duplicate_node(old_node, convert_viewport_ofs_to_graph_ofs(new_group_center + old_node.rect_position - old_group_center)) + select_node_ex(new_node, false) + old_to_new[old_node] = new_node + + # Connecte les nouveaux nodes comme les anciens. + connect_duplicated_nodes(old_to_new) + + +############ +## DELETE ## +############ + +func delete_node(node: ImageGraphNode): + assert(node) + remove_node_connections(node) + deselect_node(node) + node.queue_free() + + +func _on_GraphEdit_delete_nodes_request(node_names: Array): + for node_name in node_names: + var node = get_node(node_name) + assert(node) + deselect_node(node) + delete_node(node) + + +############### +## SAVE/LOAD ## +############### + +func clear_graph(): + deselect_all_nodes() + clear_connections() + var nodes = get_children() + for node in nodes: + if node is ImageGraphNode: + remove_child(node) + node.queue_free() + + +func new_file(): + clear_graph() + current_file_name = DEFAULT_FILENAME + current_path = "" + update_main_window_title() + + +func init_graph(graph_data: GraphData): + clear_graph() + + # Nodes + for node_data in graph_data.nodes: + var new_node: ImageGraphNode = graph_node.instance() + new_node.set_name(node_data.name) + new_node.rect_size = node_data.rect_size + add_child(new_node, true) # /!\ before assigning data + new_node.offset = node_data.offset + new_node.set_extra_data(node_data.extra_data) + + # Connexions + for connection in graph_data.connections: + var err = connect_node(connection.from, connection.from_port, connection.to, connection.to_port) + if err != OK: + print("Error loading graph: ", err) + + var from_node: ImageGraphNode = get_node(connection.from) + var to_node: ImageGraphNode = get_node(connection.to) + assert(from_node) + assert(to_node) + from_node.next_node = to_node + + +func save_graph(path: String): + # Crée et remplit un nouvau GraphData avec les données du grap et de ses nodes. + var graph_data = GraphData.new() + assert(graph_data) + + # Version number + graph_data.version = FILE_VERSION + + # Graph nodes + for node in get_children(): + if node is ImageGraphNode: + var node_data = GraphNodeData.new() + assert(node_data) + node_data.name = node.name + node_data.offset = node.offset + node_data.rect_size = node.rect_size + node_data.extra_data = node.get_extra_data() + graph_data.nodes.append(node_data) + + # Connexions + graph_data.connections = get_connection_list() + + # Crée le directory s'il n'existe pas. + var dir_path: String = path.get_base_dir() + var dir = Directory.new() + if not dir.dir_exists(dir_path): + dir.make_dir_recursive(dir_path) + if not dir.dir_exists(dir_path): + print("Makedir failed") + return + + # Sauvegarde graph_data dans le directory donné sous le nom donné. + var err = ResourceSaver.save(path, graph_data) + if err != OK: + print("Error saving graph: ", err) + return + + current_file_name = path.get_file() + current_path = path + update_main_window_title() + + +func load_graph(path: String): + var dir = Directory.new() + if not dir.file_exists(path): + print("File ", path, " doesn't exist") + return + + if ResourceLoader.exists(path): + var graph_data = ResourceLoader.load(path) + if graph_data is GraphData: + if graph_data.version == FILE_VERSION: + init_graph(graph_data) + else: + print("Error, incompatible file version ", graph_data.version) + return + + current_file_name = path.get_file() + current_path = path + update_main_window_title() + + +func open_file(): + open_dlg.popup_centered() + + +func save_file(): + if current_path == "": + save_file_as() + else: + save_graph(current_path) + + +func save_file_as(): + save_dlg.popup_centered() + + +func _on_SaveFileDialog_file_selected(path): + move_popups_out_of_the_way() + #save_graph("user://saves/", "graph.res") + # étendre ResourceFormatSaver + save_graph(path) + + +func _on_OpenFileDialog_file_selected(path): + move_popups_out_of_the_way() + #load_graph("user://saves/", "graph.res") + # étendre ResourceFormatLoader + load_graph(path) + + +############# +## ANIMATE ## +############# + +func open_load_image_dialog(node: ImageGraphNode): + assert(node) + active_node = node + image_dlg.popup_centered() + + +func open_load_sound_dialog(node: ImageGraphNode): + assert(node) + active_node = node + sound_dlg.popup_centered() + + +func reload_node_thumbnail(node: ImageGraphNode): + assert(node) + node.reload_thumbnail_from_file() + refresh_display_dialog() + + +func reload_node_sound(node: ImageGraphNode): + assert(node) + node.reload_sound_from_file() +# refresh_display_dialog() + + +func refresh_display_dialog(): + if display_dlg.visible: + display_dlg.refresh() + + +func _on_OpenImgFileDialog_file_selected(path): + assert(active_node) + move_popups_out_of_the_way() + active_node.load_thumbnail_from_file(path) + refresh_display_dialog() + + +func _on_OpenSndFileDialog_file_selected(path): + assert(active_node) + move_popups_out_of_the_way() + active_node.load_sound_from_file(path) +# refresh_display_dialog() + + +func play_animation(): + if selected_nodes.size() != 1: + return + display_dlg.init_dialog(selected_nodes.front()) + if display_dlg.window_bounds == Rect2(): + display_dlg.popup_centered() + else: + display_dlg.popup(display_dlg.window_bounds) + + +func _on_PlayButton_pressed(): + play_animation() diff --git a/Scripts/GraphNode.gd b/Scripts/GraphNode.gd new file mode 100644 index 0000000..585c489 --- /dev/null +++ b/Scripts/GraphNode.gd @@ -0,0 +1,194 @@ +extends GraphNode +class_name ImageGraphNode + +const THUMBNAIL_WIDTH: int = 160 +const THUMBNAIL_HEIGHT: int = 90 + +var next_node: ImageGraphNode = null +var next_node_slot: int = 0 +var img_path: String +var snd_path: String +var img_texture: ImageTexture = null +var sound: AudioStream = null + +var ctrl_key_was_down: bool # Dragging + +onready var thumbnail: = $VBoxContainer/Control/TextureRect +onready var subedit: = $VBoxContainer/SubtitleEdit +onready var spinbox: = $VBoxContainer/HBoxContainer/SpinBox + + +func _ready(): + assert(thumbnail) + assert(subedit) + assert(spinbox) + + +func get_thumbnail_texture(): + return thumbnail.texture + + +func get_subtitle(): + return subedit.text + + +func get_duration() -> float: + return spinbox.get_value() + + +func get_extra_data() -> Dictionary: + var ret = { + "title": get_title(), + "img_path": img_path, + "snd_path": snd_path, + "subtitle": subedit.text, + "duration": spinbox.get_value(), + } + return ret + + +func set_extra_data(node_data: Dictionary): + set_title(node_data["title"]) + img_path = node_data["img_path"] + snd_path = node_data["snd_path"] + subedit.text = node_data["subtitle"] + spinbox.set_value(node_data["duration"]) + load_thumbnail_from_file(img_path) + if not snd_path.empty(): + load_sound_from_file(snd_path) + + +func _on_GraphNode_resize_request(new_size): + var graph = get_parent() + assert(graph is GraphEdit) + if graph.is_using_snap(): + rect_size = graph.snap_position(new_size) + else: + rect_size = new_size + + +func _on_GraphNode_close_request(): + var graph = get_parent() + assert(graph is GraphEdit) + assert(graph.has_method("delete_node")) + graph.delete_node(self) + + +func _on_TextureRect_gui_input(event): + if not event is InputEventMouseButton: + return + + if event.doubleclick: + get_parent().play_animation() + return + + if event.get_button_index() == 1: + var graph: GraphEdit = get_parent() + if event.pressed: + assert(graph) + ctrl_key_was_down = Input.is_key_pressed(KEY_CONTROL) + if selected: + if ctrl_key_was_down: + graph.deselect_node(self) + else: + graph.select_node_ex(self, !ctrl_key_was_down) # /!\ Ne lance pas de signals. + + if selected: + graph.start_dragging_selected_nodes(self) + else: + if not graph.stop_dragging_selected_nodes(): + if !ctrl_key_was_down: + graph.select_node_ex(self, true) # /!\ Ne lance pas de signals. + + +func _on_LoadButton_pressed(): + open_image_file() + + +func _on_SoundButton_pressed(): + open_sound_file() + + +func _on_DelSoundButton_pressed(): + remove_sound() + + +func _on_ReloadButton_pressed(): + reload_image_file() + reload_sound_file() + + +func update_window_title(): + #set_title(img_path.get_file()) # /!\ Resizes the window! + var file_name = img_path.get_file() + file_name = file_name.rstrip('.' + file_name.get_extension()) + set_title(file_name.right(file_name.length() - 25)) + + +func load_thumbnail_from_file(path: String): + img_path = path +# texture_rect.texture = load(path) +# texture_rect.texture.set_flags(Texture.FLAGS_DEFAULT) + var img = Image.new() + var err = img.load(path) + if err != OK: + print("Error loading image ", path, " : ", err) + return + var img_ratio: float = float(img.get_width()) / float(img.get_height()) + img.resize(THUMBNAIL_WIDTH, round(float(THUMBNAIL_WIDTH) / img_ratio), Image.INTERPOLATE_LANCZOS) + var tex = ImageTexture.new() + tex.create_from_image(img) + thumbnail.texture = tex + update_window_title() + + +func load_sound_from_file(path: String): + snd_path = path + #sound = load(path) + + var ext: = path.get_extension() + match ext: + "wav": + sound = AudioStreamSample.new() + "mp3": + sound = AudioStreamMP3.new() + "ogg": + sound = AudioStreamOGGVorbis.new() + _: + print("Error, unknown sound file extension.") + return + + var file = File.new() + file.open(path, File.READ) + var bytes = file.get_buffer(file.get_len()) + file.close() + sound.data = bytes + + +func reload_thumbnail_from_file(): + load_thumbnail_from_file(img_path) + + +func reload_sound_from_file(): + load_sound_from_file(snd_path) + + +func remove_sound(): + snd_path = "" + sound = null + + +func open_image_file(): + get_parent().open_load_image_dialog(self) + + +func open_sound_file(): + get_parent().open_load_sound_dialog(self) + + +func reload_image_file(): + get_parent().reload_node_thumbnail(self) + + +func reload_sound_file(): + get_parent().reload_node_sound(self) diff --git a/Scripts/GraphNodeData.gd b/Scripts/GraphNodeData.gd new file mode 100644 index 0000000..67ec939 --- /dev/null +++ b/Scripts/GraphNodeData.gd @@ -0,0 +1,7 @@ +extends Resource +class_name GraphNodeData + +export var name: String +export var offset: Vector2 +export var rect_size: Vector2 +export var extra_data = {} diff --git a/Scripts/Main.gd b/Scripts/Main.gd new file mode 100644 index 0000000..d185da4 --- /dev/null +++ b/Scripts/Main.gd @@ -0,0 +1,248 @@ +extends Control + +enum { + FILE_MENU_NEW, + FILE_MENU_OPEN, + FILE_MENU_SAVE, + FILE_MENU_SAVEAS, + FILE_MENU_SEPARATOR_1, + FILE_MENU_QUIT, +} + +enum { +# EDIT_MENU_CUT, + EDIT_MENU_COPY, + EDIT_MENU_PASTE, + EDIT_MENU_DUPLICATE, + EDIT_MENU_SEPARATOR_1, + EDIT_MENU_ALIGN_HORZ, + EDIT_MENU_ALIGN_VERT, + EDIT_MENU_SEPARATOR_2, + EDIT_MENU_DISTRIB_ROW, + EDIT_MENU_DISTRIB_COL, + EDIT_MENU_DISTRIB_DIAG, + EDIT_MENU_DISTRIB_GRID, + EDIT_MENU_SEPARATOR_3, + EDIT_MENU_STORE_SIZE, + EDIT_MENU_RESIZE_TO_STORED, +} + +enum { + SELEC_MENU_SELECT_ALL, + SELEC_MENU_DESELECT_ALL, + SELEC_MENU_SEPARATOR_1, + SELEC_MENU_SELECT_BEFORE, + SELEC_MENU_SELECT_AFTER, + SELEC_MENU_SELECT_CONNECTED, + SELEC_MENU_SELECT_GRAPH, +} + +enum { + HELP_MENU_HELP, + HELP_MENU_SEPARATOR_1, + HELP_MENU_WEBSITE, + HELP_MENU_SEPARATOR_2, + HELP_MENU_ABOUT, +} + +onready var file_menu_button: = $HBoxContainer/FileMenuButton +onready var edit_menu_button: = $HBoxContainer/EditMenuButton +onready var selec_menu_button: = $HBoxContainer/SelecMenuButton +onready var help_menu_button: = $HBoxContainer/HelpMenuButton +onready var graph: = $Graph +onready var help_dlg: = $HelpDialog +onready var about_dlg: = $AboutDialog + + +func _ready(): + assert(file_menu_button) + assert(edit_menu_button) + assert(selec_menu_button) + assert(help_menu_button) + assert(graph) + var popup: PopupMenu + move_popups_out_of_the_way() + + # --- File Menu --- + popup = file_menu_button.get_popup() + popup.connect("id_pressed", self, "_on_FileMenu_item_pressed") + popup.add_item("New", FILE_MENU_NEW, KEY_N | KEY_MASK_CTRL) + popup.add_item("Open...", FILE_MENU_OPEN, KEY_O | KEY_MASK_CTRL) + popup.add_item("Save", FILE_MENU_SAVE, KEY_S | KEY_MASK_CTRL) + popup.add_item("Save As...", FILE_MENU_SAVEAS, KEY_S | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_separator() + popup.add_item("Quit", FILE_MENU_QUIT, KEY_Q | KEY_MASK_CTRL) + + popup.set_item_tooltip(FILE_MENU_QUIT, "Come on. Really?") + + # --- Edit Menu --- + popup = edit_menu_button.get_popup() + popup.connect("id_pressed", self, "_on_EditMenu_item_pressed") +# popup.add_item("Cut", EDIT_MENU_CUT, KEY_X | KEY_MASK_CTRL) + popup.add_item("Copy", EDIT_MENU_COPY, KEY_C | KEY_MASK_CTRL) + popup.add_item("Paste", EDIT_MENU_PASTE, KEY_V | KEY_MASK_CTRL) + popup.add_item("Duplicate", EDIT_MENU_DUPLICATE, KEY_D | KEY_MASK_CTRL) + popup.add_separator() + popup.add_item("Align Horizontally", EDIT_MENU_ALIGN_HORZ, KEY_X)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_item("Align Vertically", EDIT_MENU_ALIGN_VERT, KEY_Y)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_separator() + popup.add_item("Distribute Horizontally", EDIT_MENU_DISTRIB_ROW, KEY_H)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_item("Distribute Vertically", EDIT_MENU_DISTRIB_COL, KEY_V)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_item("Distribute Diagonally", EDIT_MENU_DISTRIB_DIAG, KEY_D)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_item("Distribute Grid", EDIT_MENU_DISTRIB_GRID, KEY_G)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_separator() + popup.add_item("Store Size", EDIT_MENU_STORE_SIZE)#, KEY_G)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_item("Resize to Stored", EDIT_MENU_RESIZE_TO_STORED)#, KEY_G)# | KEY_MASK_CTRL | KEY_MASK_SHIFT) + + popup.set_item_tooltip(EDIT_MENU_DUPLICATE, "Duplicate selected frames.") + popup.set_item_tooltip(EDIT_MENU_ALIGN_HORZ, "Align selected frames horizontally.") + popup.set_item_tooltip(EDIT_MENU_ALIGN_VERT, "Align selected frames vertically.") + popup.set_item_tooltip(EDIT_MENU_DISTRIB_ROW, "Distribute all frames downstream of the selected frame on a single row.") + popup.set_item_tooltip(EDIT_MENU_DISTRIB_COL, "Distribute all frames downstream of the selected frame on a single column.") + popup.set_item_tooltip(EDIT_MENU_DISTRIB_DIAG, "Distribute all frames downstream of the selected frame diagonally.") + popup.set_item_tooltip(EDIT_MENU_DISTRIB_GRID, "Distribute all frames downstream of the selected frame in columns. The number of columns is defined in the spinbox at the top of the screen.") + popup.set_item_tooltip(EDIT_MENU_STORE_SIZE, "Save the selected frame's size. Compressed vertically by default.") + popup.set_item_tooltip(EDIT_MENU_RESIZE_TO_STORED, "Resize selected frames to stored size.") + + # --- Select Menu --- + popup = selec_menu_button.get_popup() + popup.connect("id_pressed", self, "_on_SelecMenu_item_pressed") + popup.add_item("Select All", SELEC_MENU_SELECT_ALL, KEY_A | KEY_MASK_CTRL) + popup.add_item("Deselect All", SELEC_MENU_DESELECT_ALL, KEY_A | KEY_MASK_CTRL | KEY_MASK_SHIFT) + popup.add_separator() + popup.add_item("Select Before", SELEC_MENU_SELECT_BEFORE, KEY_B)# | KEY_MASK_CTRL) + popup.add_item("Select After", SELEC_MENU_SELECT_AFTER, KEY_A)# | KEY_MASK_CTRL) + popup.add_item("Select Connected", SELEC_MENU_SELECT_CONNECTED, KEY_C)# | KEY_MASK_CTRL) + popup.add_item("Select Graph", SELEC_MENU_SELECT_GRAPH, KEY_I)# | KEY_MASK_CTRL) + + popup.set_item_tooltip(SELEC_MENU_SELECT_BEFORE, "Select all frames upstream of the selected frames.") + popup.set_item_tooltip(SELEC_MENU_SELECT_AFTER, "Select all frames downstream of the selected frames.") + popup.set_item_tooltip(SELEC_MENU_SELECT_CONNECTED, "Select all frames both upstream and downstream the selected frames.") + popup.set_item_tooltip(SELEC_MENU_SELECT_GRAPH, "Select all frames in the charts that include the selected frames.") + + # --- Help Menu --- + popup = help_menu_button.get_popup() + popup.connect("id_pressed", self, "_on_HelpMenu_item_pressed") + popup.add_item("Help", HELP_MENU_HELP, KEY_F1) + popup.add_separator() + popup.add_item("Website", HELP_MENU_WEBSITE) + popup.add_separator() + popup.add_item("About", HELP_MENU_ABOUT) + + +func _on_FileMenu_item_pressed(item_id: int): + match item_id: + FILE_MENU_NEW: + graph.new_file() + FILE_MENU_OPEN: + graph.open_file() + FILE_MENU_SAVE: + graph.save_file() + FILE_MENU_SAVEAS: + graph.save_file_as() + FILE_MENU_QUIT: + get_tree().quit() + + +func _on_EditMenuButton_about_to_show(): + var popup: PopupMenu = edit_menu_button.get_popup() + var num_selected: int = graph.get_num_selected_nodes() + var num_copied: int = graph.get_num_copied_nodes() +# popup.set_item_disabled(EDIT_MENU_CUT, true) + popup.set_item_disabled(EDIT_MENU_COPY, num_selected == 0) + popup.set_item_disabled(EDIT_MENU_PASTE, num_copied == 0) + popup.set_item_disabled(EDIT_MENU_DUPLICATE, num_selected == 0) + popup.set_item_disabled(EDIT_MENU_ALIGN_HORZ, num_selected < 2) + popup.set_item_disabled(EDIT_MENU_ALIGN_VERT, num_selected < 2) + popup.set_item_disabled(EDIT_MENU_DISTRIB_ROW, num_selected != 1) + popup.set_item_disabled(EDIT_MENU_DISTRIB_COL, num_selected != 1) + popup.set_item_disabled(EDIT_MENU_DISTRIB_DIAG, num_selected != 1) + popup.set_item_disabled(EDIT_MENU_DISTRIB_GRID, num_selected != 1) + popup.set_item_disabled(EDIT_MENU_STORE_SIZE, num_selected != 1) + popup.set_item_disabled(EDIT_MENU_RESIZE_TO_STORED, num_selected == 0) + + +func _on_EditMenu_item_pressed(item_id: int): + match item_id: +# EDIT_MENU_CUT: +# pass + EDIT_MENU_COPY: +# #OS.set_clipboard(string) + #emit_signal("copy_nodes_request") + graph._on_GraphEdit_copy_nodes_request() + EDIT_MENU_PASTE: +# #var str: string = OS.get_clipboard() + #emit_signal("paste_nodes_request") + graph._on_GraphEdit_paste_nodes_request() + EDIT_MENU_DUPLICATE: + graph._on_GraphEdit_duplicate_nodes_request() + EDIT_MENU_ALIGN_HORZ: + graph.align_horizontally() + EDIT_MENU_ALIGN_VERT: + graph.align_vertically() + EDIT_MENU_DISTRIB_ROW: + graph.distribute_row() + EDIT_MENU_DISTRIB_COL: + graph.distribute_col() + EDIT_MENU_DISTRIB_DIAG: + graph.distribute_diag() + EDIT_MENU_DISTRIB_GRID: + graph.distribute_grid() + EDIT_MENU_STORE_SIZE: + graph.set_custom_size_from_selected_node() + EDIT_MENU_RESIZE_TO_STORED: + graph.set_selected_nodes_to_custom_size() + + +func _on_SelecMenuButton_about_to_show(): + var popup: PopupMenu = selec_menu_button.get_popup() + var num_selected: int = graph.get_num_selected_nodes() + #popup.set_item_disabled(SELEC_MENU_SELECT_ALL, false) + popup.set_item_disabled(SELEC_MENU_DESELECT_ALL, num_selected == 0) + popup.set_item_disabled(SELEC_MENU_SELECT_BEFORE, num_selected == 0) + popup.set_item_disabled(SELEC_MENU_SELECT_AFTER, num_selected == 0) + popup.set_item_disabled(SELEC_MENU_SELECT_CONNECTED, num_selected == 0) + popup.set_item_disabled(SELEC_MENU_SELECT_GRAPH, num_selected == 0) + + +func _on_SelecMenu_item_pressed(item_id: int): + match item_id: + SELEC_MENU_SELECT_ALL: + graph.select_all_nodes() + SELEC_MENU_DESELECT_ALL: + graph.deselect_all_nodes() + SELEC_MENU_SELECT_BEFORE: + graph.select_all_nodes_before_selected_nodes() + SELEC_MENU_SELECT_AFTER: + graph.select_all_nodes_after_selected_nodes() + SELEC_MENU_SELECT_CONNECTED: + graph.select_all_nodes_flowing_through_selected_nodes() + SELEC_MENU_SELECT_GRAPH: + graph.select_all_interconnected_nodes_with_selected_nodes() + + +func _on_HelpMenu_item_pressed(item_id: int): + match item_id: + HELP_MENU_HELP: + help_dlg.popup_centered() + HELP_MENU_WEBSITE: + OS.shell_open("https://godotengine.org") + HELP_MENU_ABOUT: + about_dlg.popup_centered() + + +# Hack to prevent hidden popups from stealing mouse input. +func move_popups_out_of_the_way(): + var infinite_pos: = Vector2(-1e6, -1e6) + if help_dlg and not help_dlg.visible: + help_dlg.rect_position = infinite_pos + if about_dlg and not about_dlg.visible: + about_dlg.rect_position = infinite_pos + + +func _on_HelpDialog_popup_hide(): + move_popups_out_of_the_way() + + +func _on_AboutDialog_popup_hide(): + move_popups_out_of_the_way() diff --git a/Scripts/resource_queue.gd b/Scripts/resource_queue.gd new file mode 100644 index 0000000..6fa37cb --- /dev/null +++ b/Scripts/resource_queue.gd @@ -0,0 +1,145 @@ +var thread +var mutex +var sem + +var time_max = 100 # msec + +var queue = [] +var pending = {} + +func _lock(caller): + mutex.lock() + +func _unlock(caller): + mutex.unlock() + +func _post(caller): + sem.post() + +func _wait(caller): + sem.wait() + + +func queue_resource(path, p_in_front = false): + _lock("queue_resource") + if path in pending: + _unlock("queue_resource") + return + + elif ResourceLoader.has(path): + var res = ResourceLoader.load(path) + pending[path] = res + _unlock("queue_resource") + return + else: + var res = ResourceLoader.load_interactive(path) + res.set_meta("path", path) + if p_in_front: + queue.insert(0, res) + else: + queue.push_back(res) + pending[path] = res + _post("queue_resource") + _unlock("queue_resource") + return + +func cancel_resource(path): + _lock("cancel_resource") + if path in pending: + if pending[path] is ResourceInteractiveLoader: + queue.erase(pending[path]) + pending.erase(path) + _unlock("cancel_resource") + +func get_progress(path): + _lock("get_progress") + var ret = -1 + if path in pending: + if pending[path] is ResourceInteractiveLoader: + ret = float(pending[path].get_stage()) / float(pending[path].get_stage_count()) + else: + ret = 1.0 + _unlock("get_progress") + + return ret + +func is_ready(path): + var ret + _lock("is_ready") + if path in pending: + ret = !(pending[path] is ResourceInteractiveLoader) + else: + ret = false + + _unlock("is_ready") + + return ret + +func _wait_for_resource(res, path): + _unlock("wait_for_resource") + while true: + VS.flush() + OS.delay_usec(16000) # wait 1 frame + _lock("wait_for_resource") + if queue.size() == 0 || queue[0] != res: + return pending[path] + _unlock("wait_for_resource") + + +func get_resource(path): + _lock("get_resource") + if path in pending: + if pending[path] is ResourceInteractiveLoader: + var res = pending[path] + if res != queue[0]: + var pos = queue.find(res) + queue.remove(pos) + queue.insert(0, res) + + res = _wait_for_resource(res, path) + + pending.erase(path) + _unlock("return") + return res + + else: + var res = pending[path] + pending.erase(path) + _unlock("return") + return res + else: + _unlock("return") + return ResourceLoader.load(path) + +func thread_process(): + _wait("thread_process") + + _lock("process") + + while queue.size() > 0: + + var res = queue[0] + + _unlock("process_poll") + var ret = res.poll() + _lock("process_check_queue") + + if ret == ERR_FILE_EOF || ret != OK: + var path = res.get_meta("path") + if path in pending: # else it was already retrieved + pending[res.get_meta("path")] = res.get_resource() + + queue.erase(res) # something might have been put at the front of the queue while we polled, so use erase instead of remove + + _unlock("process") + + +func thread_func(u): + while true: + thread_process() + +func start(): + mutex = Mutex.new() + sem = Semaphore.new() + thread = Thread.new() + thread.start(self, "thread_func", 0) diff --git a/export_presets.cfg b/export_presets.cfg new file mode 100644 index 0000000..dcf971f --- /dev/null +++ b/export_presets.cfg @@ -0,0 +1,42 @@ +[preset.0] + +name="Windows Desktop" +platform="Windows Desktop" +runnable=true +custom_features="" +export_filter="all_resources" +include_filter="" +exclude_filter="" +export_path="../../Export/StoryboardMapper/Windows/StoryboardMapper_v0_1.exe" +script_export_mode=1 +script_encryption_key="" + +[preset.0.options] + +custom_template/debug="" +custom_template/release="" +binary_format/64_bits=true +binary_format/embed_pck=false +texture_format/bptc=false +texture_format/s3tc=true +texture_format/etc=false +texture_format/etc2=false +texture_format/no_bptc_fallbacks=true +codesign/enable=false +codesign/identity_type=0 +codesign/identity="" +codesign/password="" +codesign/timestamp=true +codesign/timestamp_server_url="" +codesign/digest_algorithm=1 +codesign/description="" +codesign/custom_options=PoolStringArray( ) +application/modify_resources=true +application/icon="" +application/file_version="" +application/product_version="" +application/company_name="" +application/product_name="" +application/file_description="" +application/copyright="" +application/trademarks="" diff --git a/icon.png b/icon.png new file mode 100644 index 0000000..c98fbb6 Binary files /dev/null and b/icon.png differ diff --git a/icon.png.import b/icon.png.import new file mode 100644 index 0000000..a4c02e6 --- /dev/null +++ b/icon.png.import @@ -0,0 +1,35 @@ +[remap] + +importer="texture" +type="StreamTexture" +path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" +metadata={ +"vram_texture": false +} + +[deps] + +source_file="res://icon.png" +dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.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=true +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=true +svg/scale=1.0 diff --git a/project.godot b/project.godot new file mode 100644 index 0000000..d5dfcf4 --- /dev/null +++ b/project.godot @@ -0,0 +1,75 @@ +; Engine configuration file. +; It's best edited using the editor UI and not directly, +; since the parameters that go here are not all obvious. +; +; Format: +; [section] ; section goes between [] +; param=value ; assign values to parameters + +config_version=4 + +_global_script_classes=[ { +"base": "WindowDialog", +"class": "DisplayDialog", +"language": "GDScript", +"path": "res://Scripts/DisplayDialog.gd" +}, { +"base": "Resource", +"class": "GraphData", +"language": "GDScript", +"path": "res://Scripts/GraphData.gd" +}, { +"base": "Resource", +"class": "GraphNodeData", +"language": "GDScript", +"path": "res://Scripts/GraphNodeData.gd" +}, { +"base": "GraphEdit", +"class": "ImageGraph", +"language": "GDScript", +"path": "res://Scripts/GraphEdit.gd" +}, { +"base": "GraphNode", +"class": "ImageGraphNode", +"language": "GDScript", +"path": "res://Scripts/GraphNode.gd" +} ] +_global_script_class_icons={ +"DisplayDialog": "", +"GraphData": "", +"GraphNodeData": "", +"ImageGraph": "", +"ImageGraphNode": "" +} + +[application] + +config/name="StoryboardMapper" +run/main_scene="res://Scenes/Main.tscn" +config/icon="res://icon.png" + +[autoload] + +AsyncImageLoader="*res://Scripts/AsyncImageLoader.gd" + +[display] + +window/size/width=1280 +window/size/height=768 + +[global] + +default=false + +[gui] + +common/drop_mouse_on_gui_input_disabled=true + +[physics] + +common/enable_pause_aware_picking=true + +[rendering] + +quality/driver/driver_name="GLES2" +environment/default_environment="res://Resources/default_env.tres"