diff --git a/.gitignore b/.gitignore index 2076d190a4..e7da4f54d6 100644 --- a/.gitignore +++ b/.gitignore @@ -123,7 +123,6 @@ GlobalConnectionShutdownDelegate*.txt **/._.DS_Store # VSCode -.vscode .vsconfig # Custom entries diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..ddb6ff85a3 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + "recommendations": [ + "visualstudiotoolsforunity.vstuc" + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000..da60e25ae2 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,10 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Attach to Unity", + "type": "vstuc", + "request": "attach" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..f403e6761d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,61 @@ +{ + "files.exclude": { + "**/.DS_Store": true, + "**/.git": true, + "**/.vs": true, + "**/.gitmodules": true, + "**/.vsconfig": true, + "**/*.booproj": true, + "**/*.pidb": true, + "**/*.suo": true, + "**/*.user": true, + "**/*.userprefs": true, + "**/*.unityproj": true, + "**/*.dll": true, + "**/*.exe": true, + "**/*.pdf": true, + "**/*.mid": true, + "**/*.midi": true, + "**/*.wav": true, + "**/*.gif": true, + "**/*.ico": true, + "**/*.jpg": true, + "**/*.jpeg": true, + "**/*.png": true, + "**/*.psd": true, + "**/*.tga": true, + "**/*.tif": true, + "**/*.tiff": true, + "**/*.3ds": true, + "**/*.3DS": true, + "**/*.fbx": true, + "**/*.FBX": true, + "**/*.lxo": true, + "**/*.LXO": true, + "**/*.ma": true, + "**/*.MA": true, + "**/*.obj": true, + "**/*.OBJ": true, + "**/*.asset": true, + "**/*.cubemap": true, + "**/*.flare": true, + "**/*.mat": true, + "**/*.meta": true, + "build/": true, + "Build/": true, + "Library/": true, + "library/": true, + "obj/": true, + "Obj/": true, + "Logs/": true, + "logs/": true, + "ProjectSettings/": true, + "UserSettings/": true, + "temp/": true, + "Temp/": true + }, + "dotnet.defaultSolution": "SEE.sln", + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "files.trimTrailingWhitespace": true +} diff --git a/Assets/Plugins/DynamicPanels.meta b/Assets/Plugins/DynamicPanels.meta index cd5ae2a33b..b392183703 100644 --- a/Assets/Plugins/DynamicPanels.meta +++ b/Assets/Plugins/DynamicPanels.meta @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8644c2c180be9c4bf84a7ff467eb0faadd90bf7cba4a1d3650026ddd53aa044d +oid sha256:bfb637ef9995c2b689a2f3ed34ef8fcfedf8e99ec5a26126b8c170c1e220f921 size 192 diff --git a/Assets/Plugins/DynamicPanels/DynamicPanels.Runtime.asmdef b/Assets/Plugins/DynamicPanels/DynamicPanels.Runtime.asmdef index 27d5f503ea..0532dee555 100644 --- a/Assets/Plugins/DynamicPanels/DynamicPanels.Runtime.asmdef +++ b/Assets/Plugins/DynamicPanels/DynamicPanels.Runtime.asmdef @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ac53381ff903058517006c8be55250207f8bcbac7cb3f01681af267ddb3e38bc -size 40 +oid sha256:3a22d2fc514f49b9a35f0624bfbc5b0299db2d954886bd4eed3d35034f3b9fea +size 102 diff --git a/Assets/Plugins/DynamicPanels/Editor/DynamicPanelsCanvasEditor.cs b/Assets/Plugins/DynamicPanels/Editor/DynamicPanelsCanvasEditor.cs index a468c9b597..cb64eca90e 100644 --- a/Assets/Plugins/DynamicPanels/Editor/DynamicPanelsCanvasEditor.cs +++ b/Assets/Plugins/DynamicPanels/Editor/DynamicPanelsCanvasEditor.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:232cb81370ac8607a362d5df9df66dd11c6c9276d1c639c247cccb156b05f781 -size 20630 +oid sha256:8235e8b2f668a857a456bbfd01102a021b698ab79e5aabf1d752d170594c726e +size 21247 diff --git a/Assets/Plugins/DynamicPanels/README.txt b/Assets/Plugins/DynamicPanels/README.txt index 5654823a9b..b87ca5b5c8 100644 --- a/Assets/Plugins/DynamicPanels/README.txt +++ b/Assets/Plugins/DynamicPanels/README.txt @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a0407d803f87f1c732df73ef373e7bf5c02c5cbda861e7fa71eef90a4b7a20c1 -size 4709 +oid sha256:27b645a98b5bdb89897b371c40b46e08c4c81383569175e1858937989c11277f +size 256 diff --git a/Assets/Plugins/DynamicPanels/Resources/DynamicPanel.prefab b/Assets/Plugins/DynamicPanels/Resources/DynamicPanel.prefab index 6bc5964f4c..f94bd83c96 100644 --- a/Assets/Plugins/DynamicPanels/Resources/DynamicPanel.prefab +++ b/Assets/Plugins/DynamicPanels/Resources/DynamicPanel.prefab @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f98c4d693df3dddf2b756ed16dd56e84feb33b256bac74654498b48f8413679 -size 12975 +oid sha256:517b0cd40e1d471200fec6da96b18c86670cb230b07be929ef4ab2f7682c8c43 +size 12542 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/AnchorZoneBase.cs b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/AnchorZoneBase.cs index 0a7ffd851d..d734765029 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/AnchorZoneBase.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/AnchorZoneBase.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e22fa66dda515cc37170096b10ca5740805eea2dcad5e29330f269b485dccded -size 1780 +oid sha256:1e2181452915e76b9c6a97e1ee4ca369b861f91a2198b50fd4f0f47777ba7197 +size 1846 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/CanvasAnchorZone.cs b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/CanvasAnchorZone.cs index f141ee9062..19ff0e86dc 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/CanvasAnchorZone.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/CanvasAnchorZone.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c14cf841e5fecedb056931b355488fcaccec81b709f7413a9f625beece528299 -size 1145 +oid sha256:5d5c7a9cbf4848fad6ebe0353e820d2fd7b4040ec2d74088ad90b0c2e6f85dbb +size 1183 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelAnchorZone.cs b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelAnchorZone.cs index f6f7c498e1..cb5ecbcca4 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelAnchorZone.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelAnchorZone.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f44d1ec80c4c7e1636f0386e734821791205434d8eac983e3a2df198fe4e6f67 -size 2611 +oid sha256:a68918a8863b176ed571a12810edc378a55e0ddb62b027218ec9ab38ab3016cb +size 2681 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelHeaderAnchorZone.cs b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelHeaderAnchorZone.cs index b4344271b1..f6e5b4098c 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelHeaderAnchorZone.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Anchoring/PanelHeaderAnchorZone.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d793e9e5b46374bde26a8287dd4599db40086dabaeb9de182d75fe6e3abab6f -size 886 +oid sha256:0c37984ea063711e391e8371a45f88c63913c7d765ce57979edfb54f5ba4e353 +size 913 diff --git a/Assets/Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas.cs b/Assets/Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas.cs index cbd9a5ccf0..d5da51b591 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/DynamicPanelsCanvas.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b9e789cc39aebd8f1352734ed562af14460865cffb36e8fb5c27c2e96fb192e7 -size 18744 +oid sha256:a75643ccb10c65aefabb1f011d48233033e5d166fa3d4e429f237c15ab88e022 +size 19378 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Grouping/IPanelGroupElement.cs b/Assets/Plugins/DynamicPanels/Scripts/Grouping/IPanelGroupElement.cs index 37bd5a95f2..5c5913691f 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Grouping/IPanelGroupElement.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Grouping/IPanelGroupElement.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:949158bd1131a964552c8797f1a41c8769c2a884ceee7a277d34c6dbc37575db -size 542 +oid sha256:27fe14b907513c6b45cb29ba44931f969c0368e497dd8c527ca4112ebc136c3b +size 562 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Grouping/PanelGroup.cs b/Assets/Plugins/DynamicPanels/Scripts/Grouping/PanelGroup.cs index a07219d307..8e2c775898 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Grouping/PanelGroup.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Grouping/PanelGroup.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f8af76c622082d23f1169ef4b62f304bf8f49efb4c2ad2103188a888d1d49be3 -size 19478 +oid sha256:caae6b466943acad050da4c4f0889c76b1c3525554e79236fc9cba2809268ff0 +size 20144 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Grouping/UnanchoredPanelGroup.cs b/Assets/Plugins/DynamicPanels/Scripts/Grouping/UnanchoredPanelGroup.cs index eb9aeefce5..edd27aae4c 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Grouping/UnanchoredPanelGroup.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Grouping/UnanchoredPanelGroup.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3ad6c84e5c8cbcfa3f832211b76a60bfd02b36ae0aa53421cfbb3ad028cf08f7 -size 2494 +oid sha256:3a0f06528fa756d1ade4e22a1493c583812b7c420e9e803c200da1ed917f26a1 +size 2604 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/NonDrawingGraphic.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/NonDrawingGraphic.cs index ffdd51151d..3eb369b5d3 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/NonDrawingGraphic.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/NonDrawingGraphic.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cbc4f3ef065b152468f11448c543141f212a1d2145185435162c75897b21503 -size 434 +oid sha256:2db76bbee2749f3d453d185f262bc01ce8cb552f049aab2b16e2e99d4829f324 +size 452 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelCursorHandler.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelCursorHandler.cs index 7710726578..cd3f7de2a6 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelCursorHandler.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelCursorHandler.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d34d49518e88f5ff8a68e25583a4422e00008e81a112131765cb49da7e7f4f30 -size 3770 +oid sha256:f5fd9b974713d278f8087dbff136a765caf904f086488c2080db2463282bf3ed +size 3924 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelHeader.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelHeader.cs index f248698569..00ea020882 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelHeader.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelHeader.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bae1fef0a7a8ffbefb56454cf78c0e2e7a551e02e9863f604919dfc8363fc577 -size 1524 +oid sha256:9a39e823531f6bd12a210480e1a1bd8b6534e2f170bbc82b6c83452ca7238798 +size 1585 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelNotificationCenter.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelNotificationCenter.cs index caa219394c..409e7410ba 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelNotificationCenter.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelNotificationCenter.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f09530ea5728b3d0ce75efea8a0987d510b15fed70bbdc420b6b49264c7a86b6 -size 4898 +oid sha256:830fd11c327c1f1604234e2dd5c546b0811885956bb22c9fbafeff96acdb72b6 +size 5113 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelResizeHelper.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelResizeHelper.cs index fc7eee31f1..0373e49a54 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelResizeHelper.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelResizeHelper.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:74724aad5e4178bdcdbf497bf075f57649a75938e7d933cb51066509cc4c14c4 -size 3612 +oid sha256:76ed81b5d0e29ab322d2aacce460f0dbc55081ce0356660329026ae4353d5510 +size 3750 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelSerialization.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelSerialization.cs index d9b435325d..016b73b4d6 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelSerialization.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelSerialization.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:80068415964b486d44925c2e83497bed2604e2633a6dbe2df0770be9658390ed -size 9576 +oid sha256:d22df53bfc00967e54e4e9aea2f692ce9cf5aeeb96b52e3f404271a8376f55bf +size 9950 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelTab.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelTab.cs index 1a05a47e41..2cafacdeaa 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelTab.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelTab.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90830b33755db000f7bece7570eccfb22540aff53cf4bba87d7032a236e31b70 -size 5972 +oid sha256:664768824dfb710845a55a8f9b4a26fa7aa92bdc0209bf602ce2664a3689d21f +size 6230 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelUtils.cs b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelUtils.cs index 3f0bea69c0..0cef075f8f 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelUtils.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Helpers/PanelUtils.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9bb20230e01a541bf77eebb40cdd27c7d148ae947e89fedeed0d5e05f51a8467 -size 3504 +oid sha256:280173bc8035a85aeaa6455058ba57ccd5053dd4fada0152edc6253e9609b452 +size 3633 diff --git a/Assets/Plugins/DynamicPanels/Scripts/Panel.cs b/Assets/Plugins/DynamicPanels/Scripts/Panel.cs index 9198f07698..12b01cdc1b 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/Panel.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/Panel.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2ba33578d167a58ee7f9d02d123fdbfebf46a01e42d79050200e32327d1b9e8 -size 23637 +oid sha256:9f708d47883ec736007c665b8fcbb11e866bbec8cc3528aa43bb8ad8056aab20 +size 24450 diff --git a/Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs b/Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs index 8b1d6792eb..4a158cdc1b 100644 --- a/Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs +++ b/Assets/Plugins/DynamicPanels/Scripts/PanelManager.cs @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ae08a95049fd9c801eb488dcbfa6a3d6d7aa1dedeed64801fd91060d98a2c639 -size 16360 +oid sha256:3214195a0e12050543b3c993474f6769eaa3a2986d42839291c407fcd96e7d65 +size 16933 diff --git a/Assets/Plugins/DynamicPanels/Sprites/CloseButton.psd.meta b/Assets/Plugins/DynamicPanels/Sprites/CloseButton.psd.meta index 0f9b5e908f..caa815c606 100644 --- a/Assets/Plugins/DynamicPanels/Sprites/CloseButton.psd.meta +++ b/Assets/Plugins/DynamicPanels/Sprites/CloseButton.psd.meta @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d067dd7413834d32f5666a6cd2e1abf6701d6b0c3d3476918b3fe9dde800a368 -size 3689 +oid sha256:3d1f9851961cf4a18ec5edb197c861dbff3ec48020c166d9cc261fb1bc2aa726 +size 3333 diff --git a/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd b/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd index b0bff45373..103c1d8b32 100644 --- a/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd +++ b/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f7f47b3bea2c776e9d3832f1d75b9527a83fd49a80673c590f993ae447ce9e2 -size 28594 +oid sha256:f0819ac14b54c236f5d57f070e3731b47221a0739f2293218687502f1c91b612 +size 20830 diff --git a/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd.meta b/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd.meta index 8b9161ad2f..38a6a61484 100644 --- a/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd.meta +++ b/Assets/Plugins/DynamicPanels/Sprites/PanelBackground.psd.meta @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c21901cca5f8f65010d1d20cdf4aef47b06b2bde2f7a0af7f68b80a0db689503 -size 3691 +oid sha256:c21c69b8c1467aeba627ec66fbb05e965526a4461b6d2e3c2b50ecb063549c75 +size 3335 diff --git a/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd b/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd index 2dcf1d0a68..be55a59ba1 100644 --- a/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd +++ b/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:674a26e76622100a9ee6655e49029aaceb966692a0064484cb66114dd35feb8f -size 30419 +oid sha256:7102ee4e5141de8665932ed064d92b6888e4ea7197e9409bd3a3ddb4cf022dd8 +size 30455 diff --git a/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd.meta b/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd.meta index 5a029c241e..1da7ab182c 100644 --- a/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd.meta +++ b/Assets/Plugins/DynamicPanels/Sprites/PanelTabBackground.psd.meta @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2533d8cd3a4c185f921b15db01eb0e47689b3389c23f0579767d1f5a60b5c27 -size 3691 +oid sha256:4f799d41799b7c691fe7979ae9ccdffe3e63bd8cd06e685b09a3da9d9f7db40f +size 3335 diff --git a/Assets/Plugins/Parser/GenerateLexerCode.bat.meta b/Assets/Plugins/Parser/GenerateLexerCode.bat.meta index 07d7b89d66..94104109e3 100644 --- a/Assets/Plugins/Parser/GenerateLexerCode.bat.meta +++ b/Assets/Plugins/Parser/GenerateLexerCode.bat.meta @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6652ab456d19e61b67edcd4ba6e3c12bb8270f9d2d0b914a159a84cd16ebd1ba -size 326 +oid sha256:df1de65e582508ffc9103391ee947a271024b560e46a047bf2b79bd1f40c782e +size 152 diff --git a/Assets/Resources/Prefabs/Charts.meta b/Assets/Resources/Prefabs/Charts.meta index e495525440..db01f48d30 100644 --- a/Assets/Resources/Prefabs/Charts.meta +++ b/Assets/Resources/Prefabs/Charts.meta @@ -1,12 +1,8 @@ fileFormatVersion: 2 -<<<<<<< HEAD:Assets/Dependencies.meta -guid: 31815e5d24ab3b84fb9d47cacc562874 -======= guid: fb21df1ff65c7ca479f097c3034c820d ->>>>>>> origin/master:Assets/Prefabs/Charts.meta folderAsset: yes DefaultImporter: externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/PopupMenuSubMenuButton.prefab b/Assets/Resources/Prefabs/UI/PopupMenuSubMenuButton.prefab new file mode 100644 index 0000000000..b4c3703b52 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PopupMenuSubMenuButton.prefab @@ -0,0 +1,659 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &820030453018440495 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4641039880100362998} + - component: {fileID: 37939026862503639} + - component: {fileID: 6165813934536348160} + m_Layer: 5 + m_Name: Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4641039880100362998 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 820030453018440495} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8499577916647195967} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 23.3, y: 0} + m_SizeDelta: {x: 30, y: 30} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &37939026862503639 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 820030453018440495} + m_CullTransparentMesh: 0 +--- !u!114 &6165813934536348160 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 820030453018440495} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\uF05A" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4ebb98a3c87fa521a888029274c92b79, type: 2} + m_sharedMaterial: {fileID: -8620075009897487826, guid: 4ebb98a3c87fa521a888029274c92b79, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 30 + m_fontSizeBase: 30 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &1272595426619240444 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8499577916647195967} + - component: {fileID: 5054268177811721389} + - component: {fileID: 6389154563960229086} + - component: {fileID: 427450053229378955} + - component: {fileID: 8658436434225420978} + m_Layer: 5 + m_Name: PopupMenuSubMenuButton + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8499577916647195967 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1272595426619240444} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4641039880100362998} + - {fileID: 4683048119979389847} + - {fileID: 8452244492862562955} + - {fileID: 5586743027034129599} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 55} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5054268177811721389 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1272595426619240444} + m_CullTransparentMesh: 0 +--- !u!114 &6389154563960229086 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1272595426619240444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0.39215687} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 427450053229378955} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &427450053229378955 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1272595426619240444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.33333334, g: 0.37254903, b: 0.4509804, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 12 +--- !u!114 &8658436434225420978 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1272595426619240444} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a12ddbc47b17cd478cb447d1113a22b, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonText: Test Action + clickEvent: + m_PersistentCalls: + m_Calls: [] + hoverEvent: + m_PersistentCalls: + m_Calls: [] + hoverSound: {fileID: 0} + clickSound: {fileID: 0} + buttonVar: {fileID: 0} + normalText: {fileID: 792250872584375360} + soundSource: {fileID: 0} + rippleParent: {fileID: 7494196715945445660} + useCustomContent: 0 + enableButtonSounds: 0 + useHoverSound: 1 + useClickSound: 1 + useRipple: 1 + rippleUpdateMode: 1 + rippleShape: {fileID: 0} + speed: 1 + maxSize: 4 + startColor: {r: 1, g: 1, b: 1, a: 1} + transitionColor: {r: 1, g: 1, b: 1, a: 0} + renderOnTop: 0 + centered: 0 +--- !u!1 &1970246436482945221 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5586743027034129599} + - component: {fileID: 5761857674070296453} + - component: {fileID: 7538378613054711224} + m_Layer: 5 + m_Name: RightIcon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &5586743027034129599 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1970246436482945221} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8499577916647195967} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -40, y: 0} + m_SizeDelta: {x: 20, y: 20} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5761857674070296453 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1970246436482945221} + m_CullTransparentMesh: 0 +--- !u!114 &7538378613054711224 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1970246436482945221} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\uF05A" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4ebb98a3c87fa521a888029274c92b79, type: 2} + m_sharedMaterial: {fileID: -8620075009897487826, guid: 4ebb98a3c87fa521a888029274c92b79, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 20 + m_fontSizeBase: 20 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &4359041347979151087 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4683048119979389847} + - component: {fileID: 5059500120611322657} + - component: {fileID: 792250872584375360} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4683048119979389847 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4359041347979151087} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8499577916647195967} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: -2.5, y: 0} + m_SizeDelta: {x: -95, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5059500120611322657 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4359041347979151087} + m_CullTransparentMesh: 0 +--- !u!114 &792250872584375360 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4359041347979151087} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Test Action + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 84dd14695854bbc43a5faa24fcf93d0d, type: 2} + m_sharedMaterial: {fileID: 21261991626553910, guid: 84dd14695854bbc43a5faa24fcf93d0d, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 18 + m_fontSizeBase: 22.5 + m_fontWeight: 400 + m_enableAutoSizing: 1 + m_fontSizeMin: 18 + m_fontSizeMax: 23 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 1 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &7494196715945445660 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8452244492862562955} + - component: {fileID: 8817740310236070429} + - component: {fileID: 1667475523720144969} + - component: {fileID: 8929932097463880863} + m_Layer: 5 + m_Name: Ripple + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8452244492862562955 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7494196715945445660} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8499577916647195967} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8817740310236070429 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7494196715945445660} + m_CullTransparentMesh: 0 +--- !u!114 &1667475523720144969 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7494196715945445660} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 951352f31055aae46b6e9786313c632d, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 12 +--- !u!114 &8929932097463880863 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7494196715945445660} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 diff --git a/Assets/Resources/Prefabs/UI/PopupMenuSubMenuButton.prefab.meta b/Assets/Resources/Prefabs/UI/PopupMenuSubMenuButton.prefab.meta new file mode 100644 index 0000000000..c8e8743605 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PopupMenuSubMenuButton.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 91ef025b2e6b81541b7dd4634f41651e +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/PropertyGroupItem.prefab b/Assets/Resources/Prefabs/UI/PropertyGroupItem.prefab new file mode 100644 index 0000000000..f4b82b8127 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PropertyGroupItem.prefab @@ -0,0 +1,463 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &3221561598132462901 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3766619498664164433} + - component: {fileID: 6994604829827172676} + - component: {fileID: 8043074890402026029} + m_Layer: 5 + m_Name: PropertyGroupItem + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3766619498664164433 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3221561598132462901} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7801144434069277683} + - {fileID: 766617590976963954} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0, y: 1} +--- !u!114 &6994604829827172676 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3221561598132462901} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 6592963879312978613} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &8043074890402026029 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3221561598132462901} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 52dd8aaa3b5d4058ac1b1e9242d35f57, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!1 &6543745927510804026 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4151804783001895320} + - component: {fileID: 3158015502856716037} + - component: {fileID: 8716019332972553389} + m_Layer: 5 + m_Name: Expand Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4151804783001895320 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6543745927510804026} + m_LocalRotation: {x: 0, y: 0, z: -0.7071068, w: 0.7071068} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 766617590976963954} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: -90} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 0, y: 0.5} + m_AnchoredPosition: {x: 15, y: 0} + m_SizeDelta: {x: 25, y: 35} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3158015502856716037 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6543745927510804026} + m_CullTransparentMesh: 1 +--- !u!114 &8716019332972553389 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6543745927510804026} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.6901961, g: 0.6901961, b: 0.6901961, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 4b835e6972939d148aa7acfed964b9a6, type: 3} + m_Type: 0 + m_PreserveAspect: 1 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &8015187158269920060 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6174073020406636757} + - component: {fileID: 9133677281363212946} + - component: {fileID: 8844280093565481701} + m_Layer: 5 + m_Name: AttributeLine + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6174073020406636757 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8015187158269920060} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 766617590976963954} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -100, y: 40} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &9133677281363212946 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8015187158269920060} + m_CullTransparentMesh: 1 +--- !u!114 &8844280093565481701 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8015187158269920060} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: IfYouCanSeeThisIDidSomethingWrongThisIsJustAVeryLongStringOfTextToTestTheOverflowCapabilitiesOfThisTextMeshProObjectSoTheHopeIsThatTheTextDoesNotOverflowBeyondTheBoundsOfTheItem + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 79459efec17a4d00a321bdcc27bbc385, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 18 + m_fontSizeBase: 26 + m_fontWeight: 400 + m_enableAutoSizing: 1 + m_fontSizeMin: 18 + m_fontSizeMax: 30 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &8476088519983172622 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 766617590976963954} + m_Layer: 5 + m_Name: Foreground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &766617590976963954 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8476088519983172622} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 4151804783001895320} + - {fileID: 6174073020406636757} + m_Father: {fileID: 3766619498664164433} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &8970180186745827142 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7801144434069277683} + - component: {fileID: 5745935338147661148} + - component: {fileID: 6592963879312978613} + - component: {fileID: 2899379093387412028} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7801144434069277683 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8970180186745827142} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 3766619498664164433} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5745935338147661148 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8970180186745827142} + m_CullTransparentMesh: 1 +--- !u!114 &6592963879312978613 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8970180186745827142} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!114 &2899379093387412028 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8970180186745827142} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a9d2f9067277ade4e9b47012ea4d9e17, type: 3} + m_Name: + m_EditorClassIdentifier: + _gradientType: 0 + _blendMode: 2 + _modifyVertices: 0 + _offset: 0 + _zoom: 1 + _effectGradient: + serializedVersion: 2 + key0: {r: 0, g: 0.15059185, b: 1, a: 1} + key1: {r: 0, g: 0.0724779, b: 0.5803922, a: 1} + key2: {r: 0, g: 0.0724779, b: 0.5803922, a: 1} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 65535 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 65535 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 2 + m_ColorSpace: 0 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 diff --git a/Assets/Resources/Prefabs/UI/PropertyGroupItem.prefab.meta b/Assets/Resources/Prefabs/UI/PropertyGroupItem.prefab.meta new file mode 100644 index 0000000000..f8fa8ec539 --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PropertyGroupItem.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 738f21c9185c957488977a5b634dbc8b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/PropertyRowLine.prefab b/Assets/Resources/Prefabs/UI/PropertyRowLine.prefab new file mode 100644 index 0000000000..a3f044d94e --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PropertyRowLine.prefab @@ -0,0 +1,473 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4232413688770282557 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4417611932811040179} + - component: {fileID: 7221035067078308661} + m_Layer: 5 + m_Name: PropertyRowLine + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4417611932811040179 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4232413688770282557} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 804944811992268710} + - {fileID: 583018592755812378} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7221035067078308661 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4232413688770282557} + m_CullTransparentMesh: 1 +--- !u!1 &5351844536383209910 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8247726193395324134} + - component: {fileID: 3220663573982420325} + - component: {fileID: 3499561155651974852} + m_Layer: 5 + m_Name: AttributeLine + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8247726193395324134 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5351844536383209910} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 583018592755812378} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 7.5, y: 0} + m_SizeDelta: {x: -15, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3220663573982420325 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5351844536383209910} + m_CullTransparentMesh: 1 +--- !u!114 &3499561155651974852 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5351844536383209910} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Attribute + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 79459efec17a4d00a321bdcc27bbc385, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 19.95 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 1 + m_fontSizeMin: 18 + m_fontSizeMax: 30 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 20, y: 0, z: -109.62303, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &5451767514778989835 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 804944811992268710} + - component: {fileID: 2395147641264057623} + - component: {fileID: 2323185834611997723} + - component: {fileID: 8683645501149662081} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &804944811992268710 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5451767514778989835} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 4417611932811040179} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2395147641264057623 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5451767514778989835} + m_CullTransparentMesh: 1 +--- !u!114 &2323185834611997723 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5451767514778989835} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1344c3c82d62a2a41a3576d8abb8e3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Texture: {fileID: 0} + m_UVRect: + serializedVersion: 2 + x: 0 + y: 0 + width: 1 + height: 1 +--- !u!114 &8683645501149662081 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5451767514778989835} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a9d2f9067277ade4e9b47012ea4d9e17, type: 3} + m_Name: + m_EditorClassIdentifier: + _gradientType: 0 + _blendMode: 2 + _modifyVertices: 0 + _offset: 0 + _zoom: 1 + _effectGradient: + serializedVersion: 2 + key0: {r: 0, g: 0.15059185, b: 1, a: 1} + key1: {r: 0, g: 0.0724779, b: 0.5803922, a: 1} + key2: {r: 0, g: 0.0724779, b: 0.5803922, a: 1} + key3: {r: 0, g: 0, b: 0, a: 0} + key4: {r: 0, g: 0, b: 0, a: 0} + key5: {r: 0, g: 0, b: 0, a: 0} + key6: {r: 0, g: 0, b: 0, a: 0} + key7: {r: 0, g: 0, b: 0, a: 0} + ctime0: 0 + ctime1: 65535 + ctime2: 65535 + ctime3: 0 + ctime4: 0 + ctime5: 0 + ctime6: 0 + ctime7: 0 + atime0: 0 + atime1: 65535 + atime2: 65535 + atime3: 0 + atime4: 0 + atime5: 0 + atime6: 0 + atime7: 0 + m_Mode: 2 + m_ColorSpace: 0 + m_NumColorKeys: 2 + m_NumAlphaKeys: 2 +--- !u!1 &6677135121746064833 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2256359333229225443} + - component: {fileID: 5575769617067488252} + - component: {fileID: 5791917304804281608} + m_Layer: 5 + m_Name: ValueLine + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2256359333229225443 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6677135121746064833} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 583018592755812378} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: -7.5, y: 0} + m_SizeDelta: {x: -15, y: 50} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5575769617067488252 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6677135121746064833} + m_CullTransparentMesh: 1 +--- !u!114 &5791917304804281608 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6677135121746064833} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Value + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2} + m_sharedMaterial: {fileID: 2100000, guid: 79459efec17a4d00a321bdcc27bbc385, type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4278190080 + m_fontColor: {r: 0, g: 0, b: 0, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 18 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 1 + m_fontSizeMin: 18 + m_fontSizeMax: 30 + m_fontStyle: 0 + m_HorizontalAlignment: 4 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 198.69238, y: 0, z: 16.507019, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &7935205825449248997 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 583018592755812378} + m_Layer: 5 + m_Name: Foreground + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &583018592755812378 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7935205825449248997} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8247726193395324134} + - {fileID: 2256359333229225443} + m_Father: {fileID: 4417611932811040179} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0.5} + m_AnchorMax: {x: 1, y: 0.5} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 0.5} diff --git a/Assets/Resources/Prefabs/UI/PropertyRowLine.prefab.meta b/Assets/Resources/Prefabs/UI/PropertyRowLine.prefab.meta new file mode 100644 index 0000000000..6968ae97dc --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PropertyRowLine.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c3315def80cb34b41a42daf3a52848b8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Resources/Prefabs/UI/PropertyWindow.prefab b/Assets/Resources/Prefabs/UI/PropertyWindow.prefab new file mode 100644 index 0000000000..6381ad29ce --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PropertyWindow.prefab @@ -0,0 +1,2910 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &709606682935592078 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1089177651062366406} + - component: {fileID: 5618579176187327547} + - component: {fileID: 6969816262348232183} + m_Layer: 5 + m_Name: Items + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1089177651062366406 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709606682935592078} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1176873081988812620} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &5618579176187327547 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709606682935592078} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 59f8146938fff824cb5fd77236b75775, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 5 + m_Right: 10 + m_Top: 5 + m_Bottom: 5 + m_ChildAlignment: 0 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 0 + m_ChildControlWidth: 1 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 +--- !u!114 &6969816262348232183 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 709606682935592078} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3245ec927659c4140ac4f8d17403cc18, type: 3} + m_Name: + m_EditorClassIdentifier: + m_HorizontalFit: 0 + m_VerticalFit: 1 +--- !u!1 &842318586328925508 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4599480176814839446} + - component: {fileID: 388032255706994378} + - component: {fileID: 4618368004867492041} + m_Layer: 5 + m_Name: Placeholder + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &4599480176814839446 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 842318586328925508} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6690282667262079164} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 15, y: 0.5} + m_SizeDelta: {x: -30, y: -1} + m_Pivot: {x: 0, y: 0.5} +--- !u!222 &388032255706994378 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 842318586328925508} + m_CullTransparentMesh: 0 +--- !u!114 &4618368004867492041 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 842318586328925508} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: Search... + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4bd810f1cbcb0f446a8f5a31453e243f, type: 2} + m_sharedMaterial: {fileID: 21539420542967178, guid: 4bd810f1cbcb0f446a8f5a31453e243f, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 2952790015 + m_fontColor: {r: 1, g: 1, b: 1, a: 0.6862745} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 28 + m_fontSizeBase: 28 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 1 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &1837815958501779517 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7563112671056238965} + - component: {fileID: 3089042720783283610} + - component: {fileID: 3525724078483443591} + m_Layer: 5 + m_Name: Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7563112671056238965 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1837815958501779517} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1841548754507413200} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -25, y: -25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3089042720783283610 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1837815958501779517} + m_CullTransparentMesh: 0 +--- !u!114 &3525724078483443591 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1837815958501779517} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\uF0B0" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4ebb98a3c87fa521a888029274c92b79, type: 2} + m_sharedMaterial: {fileID: -8620075009897487826, guid: 4ebb98a3c87fa521a888029274c92b79, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &1874176378163580936 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7136314229054424447} + - component: {fileID: 5555767391713249978} + - component: {fileID: 7231648946806373039} + - component: {fileID: 7734883416778855734} + - component: {fileID: 4547095341203468177} + - component: {fileID: 6439533209827356462} + m_Layer: 5 + m_Name: Group + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7136314229054424447 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874176378163580936} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7073849410189226427} + - {fileID: 6855993087584589959} + m_Father: {fileID: 8455627934270354126} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 55} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &5555767391713249978 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874176378163580936} + m_CullTransparentMesh: 0 +--- !u!114 &7231648946806373039 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874176378163580936} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0.39215687} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 7734883416778855734} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &7734883416778855734 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874176378163580936} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.33333334, g: 0.37254903, b: 0.4509804, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5e16c7aea118d68498053518146c9cf9, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 13 +--- !u!114 &4547095341203468177 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874176378163580936} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a12ddbc47b17cd478cb447d1113a22b, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonText: "\uF5FD" + clickEvent: + m_PersistentCalls: + m_Calls: [] + hoverEvent: + m_PersistentCalls: + m_Calls: [] + hoverSound: {fileID: 0} + clickSound: {fileID: 0} + buttonVar: {fileID: 0} + normalText: {fileID: 8146306459036859299} + soundSource: {fileID: 0} + rippleParent: {fileID: 6395484848576167605} + useCustomContent: 0 + enableButtonSounds: 0 + useHoverSound: 1 + useClickSound: 1 + useRipple: 1 + rippleUpdateMode: 1 + rippleShape: {fileID: 0} + speed: 1 + maxSize: 4 + startColor: {r: 1, g: 1, b: 1, a: 1} + transitionColor: {r: 1, g: 1, b: 1, a: 0} + renderOnTop: 0 + centered: 0 +--- !u!114 &6439533209827356462 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1874176378163580936} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: 55 + m_MinHeight: -1 + m_PreferredWidth: 55 + m_PreferredHeight: -1 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!1 &1959865772248175663 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7739412744805412235} + - component: {fileID: 7909130829181353198} + - component: {fileID: 7427878997772969028} + - component: {fileID: 8280760184951877564} + - component: {fileID: 8663104550250191} + - component: {fileID: 2180345664057754735} + m_Layer: 5 + m_Name: Sort + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7739412744805412235 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959865772248175663} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6965380495096359521} + - {fileID: 3595538001728667684} + m_Father: {fileID: 8455627934270354126} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 55} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7909130829181353198 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959865772248175663} + m_CullTransparentMesh: 0 +--- !u!114 &7427878997772969028 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959865772248175663} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0.39215687} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8280760184951877564} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &8280760184951877564 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959865772248175663} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.33333334, g: 0.37254903, b: 0.4509804, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5e16c7aea118d68498053518146c9cf9, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 13 +--- !u!114 &8663104550250191 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959865772248175663} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a12ddbc47b17cd478cb447d1113a22b, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonText: "\uF0DC" + clickEvent: + m_PersistentCalls: + m_Calls: [] + hoverEvent: + m_PersistentCalls: + m_Calls: [] + hoverSound: {fileID: 0} + clickSound: {fileID: 0} + buttonVar: {fileID: 0} + normalText: {fileID: 4794745068905858350} + soundSource: {fileID: 0} + rippleParent: {fileID: 9041207098413024880} + useCustomContent: 0 + enableButtonSounds: 0 + useHoverSound: 1 + useClickSound: 1 + useRipple: 1 + rippleUpdateMode: 1 + rippleShape: {fileID: 0} + speed: 1 + maxSize: 4 + startColor: {r: 1, g: 1, b: 1, a: 1} + transitionColor: {r: 1, g: 1, b: 1, a: 0} + renderOnTop: 0 + centered: 0 +--- !u!114 &2180345664057754735 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1959865772248175663} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: 55 + m_MinHeight: -1 + m_PreferredWidth: 55 + m_PreferredHeight: -1 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!1 &2125963005985707447 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7412864419818588360} + - component: {fileID: 3850865178301769102} + - component: {fileID: 1051915075008402236} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7412864419818588360 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2125963005985707447} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 612935842169716872} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3850865178301769102 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2125963005985707447} + m_CullTransparentMesh: 0 +--- !u!114 &1051915075008402236 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2125963005985707447} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.09803922} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5618123237d1d3f49a5a6025287065f7, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 15 +--- !u!1 &2441149418491542768 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1841548754507413200} + - component: {fileID: 8114760013786331298} + - component: {fileID: 8202626990950085013} + - component: {fileID: 8017296535842955226} + - component: {fileID: 1208407751294909222} + - component: {fileID: 8156587985265908029} + m_Layer: 5 + m_Name: Filter + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1841548754507413200 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2441149418491542768} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7563112671056238965} + - {fileID: 2393231344255378604} + m_Father: {fileID: 8455627934270354126} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 55} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &8114760013786331298 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2441149418491542768} + m_CullTransparentMesh: 0 +--- !u!114 &8202626990950085013 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2441149418491542768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.84313726, g: 0.84313726, b: 0.84313726, a: 1} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0.39215687} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 8017296535842955226} + m_OnClick: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &8017296535842955226 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2441149418491542768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 0.33333334, g: 0.37254903, b: 0.4509804, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5e16c7aea118d68498053518146c9cf9, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 13 +--- !u!114 &1208407751294909222 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2441149418491542768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1a12ddbc47b17cd478cb447d1113a22b, type: 3} + m_Name: + m_EditorClassIdentifier: + buttonText: "\uF0B0" + clickEvent: + m_PersistentCalls: + m_Calls: [] + hoverEvent: + m_PersistentCalls: + m_Calls: [] + hoverSound: {fileID: 0} + clickSound: {fileID: 0} + buttonVar: {fileID: 0} + normalText: {fileID: 3525724078483443591} + soundSource: {fileID: 0} + rippleParent: {fileID: 6040598831507082404} + useCustomContent: 0 + enableButtonSounds: 0 + useHoverSound: 1 + useClickSound: 1 + useRipple: 1 + rippleUpdateMode: 1 + rippleShape: {fileID: 0} + speed: 1 + maxSize: 4 + startColor: {r: 1, g: 1, b: 1, a: 1} + transitionColor: {r: 1, g: 1, b: 1, a: 0} + renderOnTop: 0 + centered: 0 +--- !u!114 &8156587985265908029 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2441149418491542768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: 55 + m_MinHeight: -1 + m_PreferredWidth: 55 + m_PreferredHeight: -1 + m_FlexibleWidth: -1 + m_FlexibleHeight: -1 + m_LayoutPriority: 1 +--- !u!1 &2468651571960220266 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1176873081988812620} + - component: {fileID: 2060077036330234244} + - component: {fileID: 6932287645544762951} + - component: {fileID: 3122064075779552067} + m_Layer: 5 + m_Name: Content + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &1176873081988812620 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2468651571960220266} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1089177651062366406} + - {fileID: 2230885584348632300} + - {fileID: 612935842169716872} + m_Father: {fileID: 6068148083340061293} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -30} + m_SizeDelta: {x: 0, y: -60} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!114 &2060077036330234244 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2468651571960220266} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!222 &6932287645544762951 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2468651571960220266} + m_CullTransparentMesh: 1 +--- !u!114 &3122064075779552067 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2468651571960220266} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!1 &2689018009846703236 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8793840307802463971} + - component: {fileID: 2382594265750061630} + m_Layer: 5 + m_Name: Text Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8793840307802463971 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2689018009846703236} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8397262446398887593} + m_Father: {fileID: 6690282667262079164} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &2382594265750061630 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2689018009846703236} + m_CullTransparentMesh: 0 +--- !u!1 &2789169427069279165 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7349605152706409631} + - component: {fileID: 4665694166864105030} + - component: {fileID: 7726245115218372043} + m_Layer: 5 + m_Name: Filled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7349605152706409631 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2789169427069279165} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2871116414277210878} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4665694166864105030 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2789169427069279165} + m_CullTransparentMesh: 0 +--- !u!114 &7726245115218372043 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2789169427069279165} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5e16c7aea118d68498053518146c9cf9, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 0 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 10 +--- !u!1 &3452377398954294559 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6965380495096359521} + - component: {fileID: 1323069487810200289} + - component: {fileID: 4794745068905858350} + m_Layer: 5 + m_Name: Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6965380495096359521 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3452377398954294559} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7739412744805412235} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -25, y: -25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1323069487810200289 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3452377398954294559} + m_CullTransparentMesh: 0 +--- !u!114 &4794745068905858350 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3452377398954294559} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\uF0DC" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4ebb98a3c87fa521a888029274c92b79, type: 2} + m_sharedMaterial: {fileID: -8620075009897487826, guid: 4ebb98a3c87fa521a888029274c92b79, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &3892552716093057929 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2548444607870852420} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2548444607870852420 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3892552716093057929} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 9066124595810444874} + m_Father: {fileID: 2230885584348632300} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &4293368334216072556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6068148083340061293} + - component: {fileID: 1489559290100196060} + - component: {fileID: 2394539210909514289} + - component: {fileID: 8084997774507780795} + - component: {fileID: 4502254089515244849} + - component: {fileID: 7147490681011772360} + m_Layer: 5 + m_Name: PropertyWindow + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6068148083340061293 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4293368334216072556} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1176873081988812620} + - {fileID: 8455627934270354126} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1489559290100196060 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4293368334216072556} + m_CullTransparentMesh: 0 +--- !u!114 &2394539210909514289 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4293368334216072556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1aa08ab6e0800fa44ae55d278d1423e3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Content: {fileID: 1089177651062366406} + m_Horizontal: 1 + m_Vertical: 1 + m_MovementType: 2 + m_Elasticity: 0.1 + m_Inertia: 1 + m_DecelerationRate: 0.135 + m_ScrollSensitivity: 20 + m_Viewport: {fileID: 1176873081988812620} + m_HorizontalScrollbar: {fileID: 7171935558317943900} + m_VerticalScrollbar: {fileID: 5270351434699486664} + m_HorizontalScrollbarVisibility: 1 + m_VerticalScrollbarVisibility: 0 + m_HorizontalScrollbarSpacing: 0 + m_VerticalScrollbarSpacing: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &8084997774507780795 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4293368334216072556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 0} + m_Type: 0 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 1 +--- !u!114 &4502254089515244849 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4293368334216072556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!114 &7147490681011772360 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4293368334216072556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0b148fe25e99eb48b9724523833bab1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Delegates: + - eventID: 7 + callback: + m_PersistentCalls: + m_Calls: [] + - eventID: 14 + callback: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &4624945097066885423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8397262446398887593} + - component: {fileID: 7753730364065013434} + - component: {fileID: 6807727362598245007} + m_Layer: 5 + m_Name: Text + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8397262446398887593 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4624945097066885423} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8793840307802463971} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0.5} + m_SizeDelta: {x: -30, y: -1} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &7753730364065013434 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4624945097066885423} + m_CullTransparentMesh: 0 +--- !u!114 &6807727362598245007 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4624945097066885423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\u200B" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4bd810f1cbcb0f446a8f5a31453e243f, type: 2} + m_sharedMaterial: {fileID: 21539420542967178, guid: 4bd810f1cbcb0f446a8f5a31453e243f, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 28 + m_fontSizeBase: 28 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 1 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 0 + m_wordWrappingRatios: 0.4 + m_overflowMode: 1 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 1 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &4790813342650741183 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 9066124595810444874} + - component: {fileID: 4031127889731311101} + - component: {fileID: 4647380939240487652} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &9066124595810444874 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4790813342650741183} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2548444607870852420} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4031127889731311101 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4790813342650741183} + m_CullTransparentMesh: 0 +--- !u!114 &4647380939240487652 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4790813342650741183} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5618123237d1d3f49a5a6025287065f7, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 15 +--- !u!1 &5054872679682436084 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6821695238436829111} + m_Layer: 5 + m_Name: Sliding Area + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6821695238436829111 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 5054872679682436084} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2861595589771483337} + m_Father: {fileID: 612935842169716872} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!1 &6040598831507082404 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2393231344255378604} + - component: {fileID: 4371395400278151273} + - component: {fileID: 2649856281260980047} + - component: {fileID: 6964319325017651106} + m_Layer: 5 + m_Name: Ripple + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2393231344255378604 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6040598831507082404} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 1841548754507413200} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4371395400278151273 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6040598831507082404} + m_CullTransparentMesh: 0 +--- !u!114 &2649856281260980047 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6040598831507082404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 951352f31055aae46b6e9786313c632d, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 12 +--- !u!114 &6964319325017651106 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6040598831507082404} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &6349326866027955733 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8522233572888455346} + - component: {fileID: 1655775987536774104} + - component: {fileID: 3650492158642856089} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8522233572888455346 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6349326866027955733} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 2230885584348632300} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -10, y: -10} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &1655775987536774104 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6349326866027955733} + m_CullTransparentMesh: 0 +--- !u!114 &3650492158642856089 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6349326866027955733} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.09803922} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5618123237d1d3f49a5a6025287065f7, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 15 +--- !u!1 &6395484848576167605 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6855993087584589959} + - component: {fileID: 3066091430910427611} + - component: {fileID: 2923783150305210301} + - component: {fileID: 574293250142884438} + m_Layer: 5 + m_Name: Ripple + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6855993087584589959 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6395484848576167605} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7136314229054424447} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3066091430910427611 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6395484848576167605} + m_CullTransparentMesh: 0 +--- !u!114 &2923783150305210301 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6395484848576167605} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 951352f31055aae46b6e9786313c632d, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 12 +--- !u!114 &574293250142884438 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6395484848576167605} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 +--- !u!1 &6567039954909992875 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2230885584348632300} + - component: {fileID: 5209801497536507958} + - component: {fileID: 5270351434699486664} + - component: {fileID: 9020326814598454113} + - component: {fileID: 6861991300802042721} + m_Layer: 5 + m_Name: Scrollbar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2230885584348632300 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6567039954909992875} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 8522233572888455346} + - {fileID: 2548444607870852420} + m_Father: {fileID: 1176873081988812620} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 1, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 20, y: 0} + m_Pivot: {x: 1, y: 0.5} +--- !u!222 &5209801497536507958 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6567039954909992875} + m_CullTransparentMesh: 0 +--- !u!114 &5270351434699486664 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6567039954909992875} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 0.78431374} + m_HighlightedColor: {r: 1, g: 1, b: 1, a: 0.9607843} + m_PressedColor: {r: 1, g: 1, b: 1, a: 1} + m_SelectedColor: {r: 1, g: 1, b: 1, a: 0.9607843} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0.39215687} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 4647380939240487652} + m_HandleRect: {fileID: 9066124595810444874} + m_Direction: 2 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &9020326814598454113 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6567039954909992875} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e098a0a519700eb4094ec2c8b9d07b30, type: 3} + m_Name: + m_EditorClassIdentifier: + UIManagerAsset: {fileID: 11400000, guid: 2a619a9609984be49b53b928dd94e61b, type: 2} + webglMode: 0 + background: {fileID: 3650492158642856089} + bar: {fileID: 4647380939240487652} +--- !u!114 &6861991300802042721 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6567039954909992875} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d0b148fe25e99eb48b9724523833bab1, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Delegates: + - eventID: 14 + callback: + m_PersistentCalls: + m_Calls: [] + - eventID: 7 + callback: + m_PersistentCalls: + m_Calls: [] +--- !u!1 &6866810925557613553 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2861595589771483337} + - component: {fileID: 787139698939415621} + - component: {fileID: 3149929187128000327} + m_Layer: 5 + m_Name: Handle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2861595589771483337 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6866810925557613553} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 6821695238436829111} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &787139698939415621 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6866810925557613553} + m_CullTransparentMesh: 0 +--- !u!114 &3149929187128000327 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6866810925557613553} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5618123237d1d3f49a5a6025287065f7, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 15 +--- !u!1 &6890249196013291024 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 612935842169716872} + - component: {fileID: 121790097987027666} + - component: {fileID: 7171935558317943900} + - component: {fileID: 5568508665376354696} + m_Layer: 5 + m_Name: HorizontalScrollbar + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &612935842169716872 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6890249196013291024} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7412864419818588360} + - {fileID: 6821695238436829111} + m_Father: {fileID: 1176873081988812620} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0.000018119812, y: 20} + m_Pivot: {x: 0.5, y: 0} +--- !u!222 &121790097987027666 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6890249196013291024} + m_CullTransparentMesh: 0 +--- !u!114 &7171935558317943900 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6890249196013291024} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2a4db7a114972834c8e4117be1d82ba3, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 0.78431374} + m_HighlightedColor: {r: 1, g: 1, b: 1, a: 0.9607843} + m_PressedColor: {r: 1, g: 1, b: 1, a: 1} + m_SelectedColor: {r: 1, g: 1, b: 1, a: 0.9607843} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0.39215687} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 3149929187128000327} + m_HandleRect: {fileID: 2861595589771483337} + m_Direction: 0 + m_Value: 0 + m_Size: 1 + m_NumberOfSteps: 0 + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] +--- !u!114 &5568508665376354696 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6890249196013291024} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: e098a0a519700eb4094ec2c8b9d07b30, type: 3} + m_Name: + m_EditorClassIdentifier: + UIManagerAsset: {fileID: 11400000, guid: 2a619a9609984be49b53b928dd94e61b, type: 2} + webglMode: 0 + background: {fileID: 1051915075008402236} + bar: {fileID: 3149929187128000327} +--- !u!1 &6980893328556673925 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2871116414277210878} + - component: {fileID: 6173206746675119111} + - component: {fileID: 6424740765246731478} + m_Layer: 5 + m_Name: Background + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &2871116414277210878 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6980893328556673925} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 7349605152706409631} + m_Father: {fileID: 6690282667262079164} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &6173206746675119111 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6980893328556673925} + m_CullTransparentMesh: 0 +--- !u!114 &6424740765246731478 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6980893328556673925} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 0.019607844} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 5e16c7aea118d68498053518146c9cf9, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 10 +--- !u!1 &7181825098309350580 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8455627934270354126} + - component: {fileID: 6605686881163477485} + m_Layer: 5 + m_Name: Search + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &8455627934270354126 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7181825098309350580} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 6690282667262079164} + - {fileID: 7136314229054424447} + - {fileID: 1841548754507413200} + - {fileID: 7739412744805412235} + m_Father: {fileID: 6068148083340061293} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 1} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: -10} + m_SizeDelta: {x: 0, y: 50} + m_Pivot: {x: 0.5, y: 1} +--- !u!114 &6605686881163477485 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7181825098309350580} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30649d3a9faa99c48a7b1166b86bf2a0, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Padding: + m_Left: 5 + m_Right: 5 + m_Top: 0 + m_Bottom: 0 + m_ChildAlignment: 3 + m_Spacing: 5 + m_ChildForceExpandWidth: 1 + m_ChildForceExpandHeight: 1 + m_ChildControlWidth: 1 + m_ChildControlHeight: 0 + m_ChildScaleWidth: 0 + m_ChildScaleHeight: 0 + m_ReverseArrangement: 0 +--- !u!1 &7475176147733851298 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6690282667262079164} + - component: {fileID: 3161791815447058949} + - component: {fileID: 7237769179235166874} + - component: {fileID: 3629503722644211611} + - component: {fileID: 790196186597391616} + - component: {fileID: 8874951550066978760} + - component: {fileID: 9004278678232372259} + m_Layer: 5 + m_Name: SearchField + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &6690282667262079164 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 2871116414277210878} + - {fileID: 4599480176814839446} + - {fileID: 8793840307802463971} + m_Father: {fileID: 8455627934270354126} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 0, y: 0} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 55} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &3161791815447058949 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_CullTransparentMesh: 0 +--- !u!114 &7237769179235166874 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2da0c512f12947e489f739169773d7ca, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 0 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 0} + m_HighlightedColor: {r: 1, g: 1, b: 1, a: 0.039215688} + m_PressedColor: {r: 1, g: 1, b: 1, a: 0.05882353} + m_SelectedColor: {r: 1, g: 1, b: 1, a: 0.039215688} + m_DisabledColor: {r: 1, g: 1, b: 1, a: 0} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Highlighted + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 7726245115218372043} + m_TextViewport: {fileID: 8793840307802463971} + m_TextComponent: {fileID: 6807727362598245007} + m_Placeholder: {fileID: 0} + m_VerticalScrollbar: {fileID: 0} + m_VerticalScrollbarEventHandler: {fileID: 0} + m_LayoutGroup: {fileID: 0} + m_ScrollSensitivity: 1 + m_ContentType: 0 + m_InputType: 0 + m_AsteriskChar: 42 + m_KeyboardType: 0 + m_LineType: 0 + m_HideMobileInput: 0 + m_HideSoftKeyboard: 0 + m_CharacterValidation: 0 + m_RegexValue: + m_GlobalPointSize: 14 + m_CharacterLimit: 0 + m_OnEndEdit: + m_PersistentCalls: + m_Calls: [] + m_OnSubmit: + m_PersistentCalls: + m_Calls: [] + m_OnSelect: + m_PersistentCalls: + m_Calls: [] + m_OnDeselect: + m_PersistentCalls: + m_Calls: [] + m_OnTextSelection: + m_PersistentCalls: + m_Calls: [] + m_OnEndTextSelection: + m_PersistentCalls: + m_Calls: [] + m_OnValueChanged: + m_PersistentCalls: + m_Calls: [] + m_OnTouchScreenKeyboardStatusChanged: + m_PersistentCalls: + m_Calls: [] + m_CaretColor: {r: 1, g: 1, b: 1, a: 1} + m_CustomCaretColor: 1 + m_SelectionColor: {r: 1, g: 1, b: 1, a: 0.09803922} + m_Text: + m_CaretBlinkRate: 0.85 + m_CaretWidth: 2 + m_ReadOnly: 0 + m_RichText: 1 + m_GlobalFontAsset: {fileID: 11400000, guid: 4bd810f1cbcb0f446a8f5a31453e243f, type: 2} + m_OnFocusSelectAll: 1 + m_ResetOnDeActivation: 1 + m_RestoreOriginalTextOnEscape: 1 + m_isRichTextEditingAllowed: 1 + m_LineLimit: 0 + m_InputValidator: {fileID: 0} +--- !u!95 &3629503722644211611 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: f02ff10900044744b851159f375542e2, type: 2} + m_CullingMode: 0 + m_UpdateMode: 2 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &790196186597391616 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: c65c7917835d8a04b94c8b906234b09e, type: 3} + m_Name: + m_EditorClassIdentifier: + inputText: {fileID: 0} + inputFieldAnimator: {fileID: 0} +--- !u!114 &8874951550066978760 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d170bc6b162fcce46a456b2011fd50b4, type: 3} + m_Name: + m_EditorClassIdentifier: + UIManagerAsset: {fileID: 11400000, guid: 2a619a9609984be49b53b928dd94e61b, type: 2} + webglMode: 0 + images: + - {fileID: 6980893328556673925} + - {fileID: 2789169427069279165} + texts: + - {fileID: 842318586328925508} + - {fileID: 4624945097066885423} +--- !u!114 &9004278678232372259 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7475176147733851298} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 306cc8c2b49d7114eaa3623786fc2126, type: 3} + m_Name: + m_EditorClassIdentifier: + m_IgnoreLayout: 0 + m_MinWidth: 100 + m_MinHeight: -1 + m_PreferredWidth: -1 + m_PreferredHeight: -1 + m_FlexibleWidth: 100 + m_FlexibleHeight: -1 + m_LayoutPriority: 3 +--- !u!1 &8709522067248902145 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7073849410189226427} + - component: {fileID: 4880555759130807316} + - component: {fileID: 8146306459036859299} + m_Layer: 5 + m_Name: Icon + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &7073849410189226427 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8709522067248902145} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7136314229054424447} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: -25, y: -25} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &4880555759130807316 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8709522067248902145} + m_CullTransparentMesh: 0 +--- !u!114 &8146306459036859299 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8709522067248902145} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 1 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_text: "\uF5FD" + m_isRightToLeft: 0 + m_fontAsset: {fileID: 11400000, guid: 4ebb98a3c87fa521a888029274c92b79, type: 2} + m_sharedMaterial: {fileID: -8620075009897487826, guid: 4ebb98a3c87fa521a888029274c92b79, + type: 2} + m_fontSharedMaterials: [] + m_fontMaterial: {fileID: 0} + m_fontMaterials: [] + m_fontColor32: + serializedVersion: 2 + rgba: 4294967295 + m_fontColor: {r: 1, g: 1, b: 1, a: 1} + m_enableVertexGradient: 0 + m_colorMode: 3 + m_fontColorGradient: + topLeft: {r: 1, g: 1, b: 1, a: 1} + topRight: {r: 1, g: 1, b: 1, a: 1} + bottomLeft: {r: 1, g: 1, b: 1, a: 1} + bottomRight: {r: 1, g: 1, b: 1, a: 1} + m_fontColorGradientPreset: {fileID: 0} + m_spriteAsset: {fileID: 0} + m_tintAllSprites: 0 + m_StyleSheet: {fileID: 0} + m_TextStyleHashCode: -1183493901 + m_overrideHtmlColors: 0 + m_faceColor: + serializedVersion: 2 + rgba: 4294967295 + m_fontSize: 36 + m_fontSizeBase: 36 + m_fontWeight: 400 + m_enableAutoSizing: 0 + m_fontSizeMin: 18 + m_fontSizeMax: 72 + m_fontStyle: 0 + m_HorizontalAlignment: 2 + m_VerticalAlignment: 512 + m_textAlignment: 65535 + m_characterSpacing: 0 + m_wordSpacing: 0 + m_lineSpacing: 0 + m_lineSpacingMax: 0 + m_paragraphSpacing: 0 + m_charWidthMaxAdj: 0 + m_enableWordWrapping: 1 + m_wordWrappingRatios: 0.4 + m_overflowMode: 0 + m_linkedTextComponent: {fileID: 0} + parentLinkedComponent: {fileID: 0} + m_enableKerning: 1 + m_enableExtraPadding: 0 + checkPaddingRequired: 0 + m_isRichText: 1 + m_parseCtrlCharacters: 1 + m_isOrthographic: 1 + m_isCullingEnabled: 0 + m_horizontalMapping: 0 + m_verticalMapping: 0 + m_uvLineOffset: 0 + m_geometrySortingOrder: 0 + m_IsTextObjectScaleStatic: 0 + m_VertexBufferAutoSizeReduction: 0 + m_useMaxVisibleDescender: 1 + m_pageToDisplay: 1 + m_margin: {x: 0, y: 0, z: 0, w: 0} + m_isUsingLegacyAnimationComponent: 0 + m_isVolumetricText: 0 + m_hasFontAssetChanged: 0 + m_baseMaterial: {fileID: 0} + m_maskOffset: {x: 0, y: 0, z: 0, w: 0} +--- !u!1 &9041207098413024880 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3595538001728667684} + - component: {fileID: 195908297805271598} + - component: {fileID: 977652172377916750} + - component: {fileID: 5913044580492746682} + m_Layer: 5 + m_Name: Ripple + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!224 &3595538001728667684 +RectTransform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9041207098413024880} + m_LocalRotation: {x: -0, y: -0, z: -0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 7739412744805412235} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} + m_AnchorMin: {x: 0, y: 0} + m_AnchorMax: {x: 1, y: 1} + m_AnchoredPosition: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 0} + m_Pivot: {x: 0.5, y: 0.5} +--- !u!222 &195908297805271598 +CanvasRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9041207098413024880} + m_CullTransparentMesh: 0 +--- !u!114 &977652172377916750 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9041207098413024880} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Material: {fileID: 0} + m_Color: {r: 1, g: 1, b: 1, a: 1} + m_RaycastTarget: 0 + m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0} + m_Maskable: 1 + m_OnCullStateChanged: + m_PersistentCalls: + m_Calls: [] + m_Sprite: {fileID: 21300000, guid: 951352f31055aae46b6e9786313c632d, type: 3} + m_Type: 1 + m_PreserveAspect: 0 + m_FillCenter: 1 + m_FillMethod: 4 + m_FillAmount: 1 + m_FillClockwise: 1 + m_FillOrigin: 0 + m_UseSpriteMesh: 0 + m_PixelsPerUnitMultiplier: 12 +--- !u!114 &5913044580492746682 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 9041207098413024880} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 31a19414c41e5ae4aae2af33fee712f6, type: 3} + m_Name: + m_EditorClassIdentifier: + m_ShowMaskGraphic: 0 diff --git a/Assets/Resources/Prefabs/UI/PropertyWindow.prefab.meta b/Assets/Resources/Prefabs/UI/PropertyWindow.prefab.meta new file mode 100644 index 0000000000..a0060c198a --- /dev/null +++ b/Assets/Resources/Prefabs/UI/PropertyWindow.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 2a322c90736c7d54d8462ef91bbc1c48 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SEE/Controls/Actions/AbstractPlayerAction.cs b/Assets/SEE/Controls/Actions/AbstractPlayerAction.cs index 8ed5385ab4..6c300346f0 100644 --- a/Assets/SEE/Controls/Actions/AbstractPlayerAction.cs +++ b/Assets/SEE/Controls/Actions/AbstractPlayerAction.cs @@ -27,6 +27,11 @@ public abstract class AbstractPlayerAction : IReversibleAction /// protected IReversibleAction.Progress CurrentState = IReversibleAction.Progress.NoEffect; + /// + /// Whether the action is executed through the context menu. + /// + public bool ExecuteViaContextMenu { get; set; } = false; + /// /// The undo operation which has to be implemented specifically by subclasses /// to revert the effect of an executed action. diff --git a/Assets/SEE/Controls/Actions/AcceptDivergenceAction.cs b/Assets/SEE/Controls/Actions/AcceptDivergenceAction.cs index c354e4960f..55b1ca98d0 100644 --- a/Assets/SEE/Controls/Actions/AcceptDivergenceAction.cs +++ b/Assets/SEE/Controls/Actions/AcceptDivergenceAction.cs @@ -1,16 +1,18 @@ -using System.Collections.Generic; +using SEE.Audio; using SEE.DataModel.DG; -using SEE.Tools.ReflexionAnalysis; -using SEE.GO; -using SEE.Utils.History; -using UnityEngine; -using System; +using SEE.Game; using SEE.Game.SceneManipulation; +using SEE.GO; using SEE.Net.Actions; -using SEE.Audio; -using SEE.Game; +using SEE.Tools.ReflexionAnalysis; +using SEE.UI.DebugAdapterProtocol.DebugAdapter; using SEE.UI.Notification; using SEE.Utils; +using SEE.Utils.History; +using System; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; namespace SEE.Controls.Actions { @@ -76,11 +78,16 @@ public Memento(Node source, Node target, string type) private Memento memento; /// - /// The edge created by this action. Can be null if no edge has been created yet or whether - /// an Undo was called. The created edge is stored only to delete it again if Undo is - /// called. All information to create the edge is kept in . + /// The information required to (re-)create the edges that solve the divergence + /// via the multi-selection context menu. /// - private Edge createdEdge; + private readonly List mementoList = new(); + + /// + /// The edges created by this action . + /// The list is needed for the multi-selection via context menu. + /// + private readonly List createdEdgeList = new(); /// /// Registers itself at to listen for hovering events. @@ -135,12 +142,12 @@ public override bool Update() // we have both source and target of the edge and use a memento struct // to remember which edge we have added memento = new Memento(source, target, Edge.SourceDependency); - + mementoList.Add(memento); // create the edge - createdEdge = CreateConvergentEdge(memento); + createdEdgeList.Add(CreateConvergentEdge(memento)); // check whether edge creation was successful - bool divergenceSolved = createdEdge != null; + bool divergenceSolved = createdEdgeList[0] != null; // add audio cue to the appearance of the new architecture edge AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.NewEdgeSound); @@ -158,6 +165,12 @@ public override bool Update() ShowNotification.Warn("Not an edge", $"Selected Element {divergentEdge.name} is not an edge.\n"); } } + if (ExecuteViaContextMenu) + { + bool divergenceSolved = createdEdgeList.All(e => e != null); + CurrentState = divergenceSolved ? IReversibleAction.Progress.Completed : IReversibleAction.Progress.NoEffect; + return true; + } return false; } @@ -167,30 +180,41 @@ public override bool Update() public override void Undo() { base.Undo(); + foreach (Edge edge in createdEdgeList) + { + RemoveDivergence(edge); + } + createdEdgeList.Clear(); + } + /// + /// Removes the divergence (undo). + /// + /// The edge divergence to remove. + /// If the edge not contained in a graph. + private void RemoveDivergence(Edge edge) + { // remove the synced edge (its info is saved in memento) - ReflexionGraph graph = (ReflexionGraph)createdEdge.ItsGraph; + ReflexionGraph graph = (ReflexionGraph)edge.ItsGraph; if (graph != null) { // find the corresponding GameObject - GameObject createdEdgeGO = GraphElementIDMap.Find(createdEdge.ID); + GameObject createdEdgeGO = GraphElementIDMap.Find(edge.ID); // remove the edge's GameObject and graph representation locally and on the network GameEdgeAdder.Remove(createdEdgeGO); // propagate the new edge via network - new DeleteNetAction(createdEdge.ID).Execute(); + new DeleteNetAction(edge.ID).Execute(); // ensure the edge's GameObject gets destroyed properly Destroyer.Destroy(createdEdgeGO); } else { - throw new Exception($"Edge {createdEdge.ID} to be removed is not contained in a graph."); + throw new Exception($"Edge {edge.ID} to be removed is not contained in a graph."); } - // set any edge references back to null - createdEdge = null; } /// @@ -199,8 +223,10 @@ public override void Undo() public override void Redo() { base.Redo(); - // recreate the edge - createdEdge = CreateConvergentEdge(memento); + foreach (Memento mem in mementoList) + { + createdEdgeList.Add(CreateConvergentEdge(mem)); + } } /// @@ -219,17 +245,46 @@ private static Edge CreateConvergentEdge(Memento memento) } /// - /// Creates a new edge in the architecture to allow the given . + /// Used to execute the from the context menu. + /// Creates a new edge in the architecture to allow the given + /// and ensures that the method performs the execution via context menu. /// /// the edge representing the divergence /// the new edge - public static Edge CreateConvergentEdge(Edge divergence) + public void ContextMenuExecution(Edge divergence) + { + ExecuteViaContextMenu = true; + mementoList.Add(CreateMementoAndConvergentEdge(divergence)); + } + + /// + /// Used to execute the from the context menu in multiselection mode. + /// Creates new edges in the architecture to allow the given and ensures + /// that the method perfoms the execution via context menu. + /// + /// The edges representing the divergences. + public void ContextMenuExecution(IList divergences) + { + ExecuteViaContextMenu = true; + foreach (Edge divergence in divergences) + { + mementoList.Add(CreateMementoAndConvergentEdge(divergence)); + } + } + + /// + /// Creates the memento for restoring the edge and creates the edge. + /// + /// the edge representing the divergence. + /// The created memento. + private Memento CreateMementoAndConvergentEdge(Edge divergence) { ReflexionGraph graph = (ReflexionGraph)divergence.ItsGraph; Node source = graph.MapsTo(divergence.Source); Node target = graph.MapsTo(divergence.Target); - Memento memento = new(source, target, Edge.SourceDependency); - return CreateConvergentEdge(memento); + memento = new(source, target, Edge.SourceDependency); + createdEdgeList.Add(CreateConvergentEdge(memento)); + return memento; } /// @@ -247,18 +302,13 @@ public override ActionStateType GetActionStateType() /// all IDs of GameObjects manipulated by this action public override HashSet GetChangedObjects() { - if (createdEdge == null) + if (createdEdgeList.Count == 0) { return new HashSet(); } else { - return new HashSet - { - memento.From.ID, - memento.To.ID, - createdEdge.ID - }; + return mementoList.Zip(createdEdgeList, (m, e) => new[] { m.From.ID, m.To.ID, e.ID }).SelectMany(x => x).ToHashSet(); } } } diff --git a/Assets/SEE/Controls/Actions/ActionStateTypes.cs b/Assets/SEE/Controls/Actions/ActionStateTypes.cs index 1ec83d88ac..b753e1ee54 100644 --- a/Assets/SEE/Controls/Actions/ActionStateTypes.cs +++ b/Assets/SEE/Controls/Actions/ActionStateTypes.cs @@ -1,5 +1,5 @@ -using SEE.Utils; -using UnityEngine; +using UnityEngine; +using SEE.Utils; using SEE.Controls.Actions.HolisticMetrics; using SEE.Controls.Actions.Drawable; @@ -95,6 +95,11 @@ static ActionStateTypes() Color.green.Darker(), Icons.PenToSquare, EditNodeAction.CreateReversibleAction); + ResizeNode = + new("Resize Node", "Change the size of a node", + Color.green.Darker(), Icons.Resize, + ResizeNodeAction.CreateReversibleAction); + ScaleNode = new("Scale Node", "Scale a node", Color.green.Darker(), Icons.Scale, @@ -110,11 +115,6 @@ static ActionStateTypes() Color.black, Icons.Code, ShowCodeAction.CreateReversibleAction); - Draw = - new("Draw", "Draw freely in world space", - Color.magenta.Darker(), Icons.Pencil, - DrawAction.CreateReversibleAction); - AcceptDivergence = new("Accept Divergence", "Accept a diverging edge into the architecture", Color.grey.Darker(), Icons.CheckedCheckbox, @@ -308,6 +308,7 @@ static ActionStateTypes() public static readonly ActionStateType NewEdge; public static readonly ActionStateType NewNode; public static readonly ActionStateType EditNode; + public static readonly ActionStateType ResizeNode; public static readonly ActionStateType ScaleNode; public static readonly ActionStateType Delete; public static readonly ActionStateType ShowCode; diff --git a/Assets/SEE/Controls/Actions/AddEdgeAction.cs b/Assets/SEE/Controls/Actions/AddEdgeAction.cs index a2abf39565..6d40aed0cb 100644 --- a/Assets/SEE/Controls/Actions/AddEdgeAction.cs +++ b/Assets/SEE/Controls/Actions/AddEdgeAction.cs @@ -175,6 +175,17 @@ public override bool Update() return result; } + /// + /// Used to execute the from the context menu. + /// It ensures that the method performs the execution via context menu. + /// + /// Is the source node of the edge. + public void ContextMenuExecution(GameObject source) + { + from = source; + ShowNotification.Info("Select target", "Next, select a target node for the line."); + } + /// /// Undoes this AddEdgeAction /// diff --git a/Assets/SEE/Controls/Actions/AddNodeAction.cs b/Assets/SEE/Controls/Actions/AddNodeAction.cs index 54b0eb62c7..686696132f 100644 --- a/Assets/SEE/Controls/Actions/AddNodeAction.cs +++ b/Assets/SEE/Controls/Actions/AddNodeAction.cs @@ -6,6 +6,9 @@ using SEE.Audio; using SEE.Game.SceneManipulation; using SEE.Utils; +using System; +using SEE.UI.PropertyDialog; +using SEE.DataModel.DG; namespace SEE.Controls.Actions { @@ -14,6 +17,43 @@ namespace SEE.Controls.Actions /// internal class AddNodeAction : AbstractPlayerAction { + /// + /// The life cycle of this add node action. + /// + private enum ProgressState + { + /// + /// Initial state when no parent node is selected. + /// + NoNodeSelected, + /// + /// A new node is created and selected, the dialog is opened, + /// and we wait for input. + /// + WaitingForInput, + /// + /// When the action is finished. + /// + Finish + } + + /// + /// The current state of the add node process. + /// + private ProgressState progress = ProgressState.NoNodeSelected; + + /// + /// The chosen parent for the new node. + /// Will be used for context menu execution. + /// + private GameObject parent; + + /// + /// The chosen position for the new node. + /// Will be used for context menu execution. + /// + private Vector3 position; + /// /// If the user clicks with the mouse hitting a game object representing a graph node, /// this graph node is a parent to which a new node is created and added as a child. @@ -24,31 +64,120 @@ public override bool Update() { bool result = false; - // FIXME: Needs adaptation for VR where no mouse is available. - if (Input.GetMouseButtonDown(0) - && Raycasting.RaycastGraphElement(out RaycastHit raycastHit, out GraphElementRef _) == HitGraphElement.Node) + switch (progress) { - // the hit object is the parent in which to create the new node - GameObject parent = raycastHit.collider.gameObject; - addedGameNode = GameNodeAdder.AddChild(parent); - // addedGameNode has the scale and position of parent. - // The position at which the parent was hit will be the center point of the addedGameNode. - addedGameNode.transform.position = raycastHit.point; - // PutOn makes sure addedGameNode fits into parent. - GameNodeMover.PutOn(child: addedGameNode.transform, parent: parent, true); - memento = new Memento(child: addedGameNode, parent: parent); - memento.NodeID = addedGameNode.name; - new AddNodeNetAction(parentID: memento.Parent.name, newNodeID: memento.NodeID, memento.Position, memento.Scale).Execute(); - result = true; - CurrentState = IReversibleAction.Progress.Completed; - AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.NewNodeSound, parent); + case ProgressState.NoNodeSelected: + if (Input.GetMouseButtonDown(0) + && Raycasting.RaycastGraphElement(out RaycastHit raycastHit, out GraphElementRef _) == HitGraphElement.Node) + { + // the hit object is the parent in which to create the new node + GameObject parent = raycastHit.collider.gameObject; + AddNode(raycastHit.collider.gameObject, raycastHit.point); + } + else if (ExecuteViaContextMenu) + { + AddNode(parent, position); + } + break; + case ProgressState.WaitingForInput: + // Waiting until the dialog is closed and all input is present. + break; + case ProgressState.Finish: + result = true; + CurrentState = IReversibleAction.Progress.Completed; + AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.NewNodeSound, parent); + break; + default: + throw new NotImplementedException($"Unhandled case {nameof(progress)}."); } return result; } + /// + /// Adds a node on the chosen at the + /// chosen . + /// + /// The parent on which to place the node. + /// The position where the node should be placed. + private void AddNode(GameObject parent, Vector3 position) + { + addedGameNode = GameNodeAdder.AddChild(parent); + // addedGameNode has the scale and position of parent. + // The position at which the parent was hit will be the center point of the addedGameNode. + // The node is scaled down and placed on top of its parent. + addedGameNode.transform.localScale = new Vector3(0.2f, 0.2f, 0.2f); + addedGameNode.transform.position = GameNodeMover.GetCoordinatesOn(addedGameNode.transform.lossyScale, position, parent); + // TODO(#786) The new node is scaled down arbitrarily and might overlap with its siblings. + memento = new(child: addedGameNode, parent: parent) + { + NodeID = addedGameNode.name + }; + new AddNodeNetAction(parentID: memento.Parent.name, newNodeID: memento.NodeID, memento.Position, memento.Scale).Execute(); + progress = ProgressState.WaitingForInput; + OpenDialog(addedGameNode.GetNode()); + } + + /// + /// Opens a dialog where the user can enter the node name and type. + /// If the user presses the OK button, the SourceName and Type of + /// will have the new values entered + /// and and + /// will be set to memorize these and is + /// moved forward to . + /// If the user presses the Cancel button, the node will be created as + /// an unnamed node with the unkown type. + /// + private void OpenDialog(Node node) + { + NodePropertyDialog dialog = new(node); + dialog.OnConfirm.AddListener(OKButtonPressed); + dialog.OnCancel.AddListener(CancelButtonPressed); + dialog.Open(true); + SEEInput.KeyboardShortcutsEnabled = false; + + return; + + void OKButtonPressed() + { + memento.Name = node.SourceName; + memento.Type = node.Type; + new EditNodeNetAction(node.ID, node.SourceName, node.Type).Execute(); + InteractableObject.UnselectAll(true); + progress = ProgressState.Finish; + SEEInput.KeyboardShortcutsEnabled = true; + } + + void CancelButtonPressed() + { + // Case when last used is used and it has a value other + // then 'UNKOWNTYPE', use it. + if (node.Type != Graph.UnknownType) + { + memento.Name = node.SourceName; + memento.Type = node.Type; + } + progress = ProgressState.Finish; + SEEInput.KeyboardShortcutsEnabled = true; + } + } + + /// + /// Used to execute the from the context menu. + /// Calls and ensures that the method + /// performs the execution via context menu. + /// + /// The parent node. + /// The position where the node should be placed. + public void ContextMenuExecution(GameObject parent, Vector3 position) + { + this.parent = parent; + this.position = position; + ExecuteViaContextMenu = true; + } + /// /// The node that was added when this action was executed. It is saved so - /// that it can be removed on Undo(). + /// that it can be removed on . /// private GameObject addedGameNode; @@ -79,6 +208,14 @@ private struct Memento /// original name of the node in Redo(). /// public string NodeID; + /// + /// The chosen name for the added node. + /// + public string Name; + /// + /// The chosen type for the added node. + /// + public string Type; /// /// Constructor setting the information necessary to re-do this action. @@ -91,11 +228,13 @@ public Memento(GameObject child, GameObject parent) Position = child.transform.position; Scale = child.transform.lossyScale; NodeID = null; + Name = string.Empty; + Type = string.Empty; } } /// - /// Undoes this AddNodeAction. + /// Undoes this action. /// public override void Undo() { @@ -110,15 +249,25 @@ public override void Undo() } /// - /// Redoes this AddNodeAction. + /// Redoes this action. /// public override void Redo() { base.Redo(); - addedGameNode = GameNodeAdder.AddChild(memento.Parent, worldSpacePosition: memento.Position, worldSpaceScale: memento.Scale, nodeID: memento.NodeID); + addedGameNode = GameNodeAdder.AddChild(memento.Parent, worldSpacePosition: memento.Position, + worldSpaceScale: memento.Scale, nodeID: memento.NodeID); if (addedGameNode != null) { - new AddNodeNetAction(parentID: memento.Parent.name, newNodeID: memento.NodeID, memento.Position, memento.Scale).Execute(); + new AddNodeNetAction(parentID: memento.Parent.name, + newNodeID: memento.NodeID, memento.Position, memento.Scale).Execute(); + + if (!string.IsNullOrEmpty(memento.Type)) + { + Node node = addedGameNode.GetNode(); + GameNodeEditor.ChangeName(node, memento.Name); + GameNodeEditor.ChangeType(node, memento.Type); + new EditNodeNetAction(node.ID, node.SourceName, node.Type).Execute(); + } } } diff --git a/Assets/SEE/Controls/Actions/ContextMenuAction.cs b/Assets/SEE/Controls/Actions/ContextMenuAction.cs index d223fda756..79f67ce4fa 100644 --- a/Assets/SEE/Controls/Actions/ContextMenuAction.cs +++ b/Assets/SEE/Controls/Actions/ContextMenuAction.cs @@ -4,7 +4,6 @@ using Cysharp.Threading.Tasks; using SEE.DataModel.DG; using SEE.Game; -using SEE.Game.SceneManipulation; using SEE.GO; using SEE.Tools.ReflexionAnalysis; using SEE.UI.Notification; @@ -14,6 +13,10 @@ using SEE.Utils; using UnityEngine; using SEE.Game.City; +using SEE.Utils.History; +using SEE.GO.Menu; +using SEE.UI.Menu.Drawable; +using SEE.UI.Window.PropertyWindow; namespace SEE.Controls.Actions { @@ -28,6 +31,21 @@ public class ContextMenuAction : MonoBehaviour private PopupMenu popupMenu; /// + /// The position where the menu should be opened. + /// + private Vector3 position; + + /// + /// The interactable object during the start must be the same as when + /// the right mouse button is released in order for the context menu to open. + /// + private InteractableObject startObject; + + /// + /// Tries to open the context menu with multiselection. + /// + private bool multiselection = false; + /// The position of the mouse when the user started opening the context menu. /// private Vector3 startMousePosition = Vector3.zero; @@ -41,36 +59,231 @@ private void Update() { if (SEEInput.OpenContextMenuStart()) { - startMousePosition = Input.mousePosition; + if (InteractableObject.SelectedObjects.Count <= 1) + { + Raycasting.RaycastInteractableObject(out _, out InteractableObject o); + startObject = o; + startMousePosition = Input.mousePosition; + multiselection = false; + } + else + { + startObject = null; + multiselection = true; + } } - else if (SEEInput.OpenContextMenuEnd() && (Input.mousePosition - startMousePosition).magnitude < 1) + if (SEEInput.OpenContextMenuEnd()) { - // TODO (#664): Detect if multiple elements are selected and adjust options accordingly. - HitGraphElement hit = Raycasting.RaycastInteractableObject(out _, out InteractableObject o); - if (hit == HitGraphElement.None) + if (!multiselection) { - return; + HitGraphElement hit = Raycasting.RaycastInteractableObject(out RaycastHit raycastHit, out InteractableObject o); + if (hit == HitGraphElement.None) + { + return; + } + if (o == startObject && (Input.mousePosition - startMousePosition).magnitude < 1) + { + position = Input.mousePosition; + IEnumerable entries = GetApplicableOptions(popupMenu, position, raycastHit.point, o.GraphElemRef.Elem, o.gameObject); + popupMenu.ShowWith(entries, position); + } + } + else + { + HitGraphElement hit = Raycasting.RaycastInteractableObject(out RaycastHit raycastHit, out InteractableObject o); + if (hit == HitGraphElement.None) + { + return; + } + if (InteractableObject.SelectedObjects.Contains(o)) + { + position = Input.mousePosition; + IEnumerable entries = GetApplicableOptionsForMultiselection(popupMenu, InteractableObject.SelectedObjects); + popupMenu.ShowWith(entries, position); + } + } + } + } + + /// + /// Updates the context menu. + /// + /// The popup menu in which the options should be displayed. + /// The position to be displayed the popup menu. + /// The new entries for the context menu. + private static void UpdateEntries(PopupMenu popupMenu, Vector3 position, IEnumerable entries) + { + popupMenu.ShowWith(entries, position); + } + + #region Multiple-Selection + /// + /// Returns the options available for multiple selection. + /// + /// The popup menu in which the options should be displayed. + /// The selected objects. + /// Options available for the selected objects. + private IEnumerable GetApplicableOptionsForMultiselection(PopupMenu popupMenu, HashSet selectedObjects) + { + List entries = new() + { + new PopupMenuHeading($"{selectedObjects.Count} elements selected!", int.MaxValue), + + new PopupMenuActionDoubleIcon("Inspect", () => + { + List submenuEntries = new() + { + new PopupMenuAction("Inspect", () => + { + UpdateEntries(popupMenu, position, GetApplicableOptionsForMultiselection(popupMenu, selectedObjects)); + }, Icons.ArrowLeft, CloseAfterClick: false), + new PopupMenuAction("Properties", ShowProperties, Icons.Info), + new PopupMenuAction("Show Metrics", ShowMetrics, Icons.Info), + new PopupMenuAction("Show in City", Highlight, Icons.LightBulb) + }; + + if (selectedObjects.Any(o => o.GraphElemRef.Elem.Filename != null)) + { + submenuEntries.Add(new PopupMenuAction("Show Code", ShowCode, Icons.Code)); + if (selectedObjects.Any(o => o.gameObject.ContainingCity() != null)) + { + submenuEntries.Add(new PopupMenuAction("Show Code Diff", ShowDiffCode, Icons.Code)); + } + } + UpdateEntries(popupMenu, position, submenuEntries); + }, + Icons.Info, Icons.ArrowRight, CloseAfterClick: false, Priority: 5), + new PopupMenuAction("Delete", Delete, Icons.Trash) + }; + + if (selectedObjects.Any(iO => iO.GraphElemRef.Elem is Edge edge && edge.IsInImplementation() && ReflexionGraph.IsDivergent(edge))) + { + entries.Add(new PopupMenuAction("Accept Divergence", AcceptDivergence, Icons.Checkmark, Priority: 1)); + } + return entries; + + void Delete() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.Delete); + DeleteAction action = (DeleteAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(selectedObjects.Select(iO => iO.gameObject)); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + + void AcceptDivergence() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.AcceptDivergence); + AcceptDivergenceAction action = (AcceptDivergenceAction)GlobalActionHistory.CurrentAction(); + List divergences = selectedObjects + .Select(x => x.GraphElemRef.Elem) + .OfType() + .Where(e => e.IsInImplementation() && ReflexionGraph.IsDivergent(e)) + .ToList(); + action.ContextMenuExecution(divergences); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + + void ShowProperties() + { + foreach (InteractableObject iO in selectedObjects) + { + if (iO.gameObject != null) + { + ActivateWindow(CreatePropertyWindow(iO.gameObject.MustGetComponent())); + } + } + } + + void ShowMetrics() + { + foreach (InteractableObject iO in selectedObjects) + { + if (iO.gameObject != null) + { + ActivateWindow(CreateMetricWindow(iO.gameObject.MustGetComponent())); + } } + } - IEnumerable actions = GetApplicableOptions(o.GraphElemRef.Elem, o.gameObject); - popupMenu.ShowWith(actions, Input.mousePosition); + void ShowCode() + { + foreach (InteractableObject iO in selectedObjects) + { + if (iO.gameObject != null) + { + ActivateWindow(ShowCodeAction.ShowCode(iO.gameObject.MustGetComponent())); + } + } + } + + void ShowDiffCode() + { + foreach (InteractableObject iO in selectedObjects) + { + if (iO.gameObject != null && iO.gameObject.ContainingCity()) + { + ActivateWindow(ShowCodeAction.ShowVCSDiff(iO.gameObject.MustGetComponent(), + iO.gameObject.ContainingCity())); + } + } + } + + void Highlight() + { + foreach (InteractableObject iO in selectedObjects) + { + if (iO.gameObject != null) + { + iO.gameObject.Operator().Highlight(duration: 10); + } + } } } + + #endregion + + #region Single-Selection /// /// Returns the options available for the given graph element. /// + /// The popup menu in which the options should be displayed. + /// The context menu position. /// The graph element to get the options for /// The game object that the graph element is attached to + /// Actions to be append at the end of the entries. /// Options available for the given graph element /// Thrown if the graph element is neither a node nor an edge - public static IEnumerable GetApplicableOptions(GraphElement graphElement, GameObject gameObject = null) + public static IEnumerable GetOptionsForTreeView(PopupMenu popupMenu, Vector3 position, + GraphElement graphElement, GameObject gameObject = null, IEnumerable appendActions = null) { - IEnumerable options = GetCommonOptions(graphElement, gameObject); + return GetApplicableOptions(popupMenu, position, position, graphElement, gameObject, appendActions) + .OfType(); + } + + /// + /// Returns the options available for the given graph element. + /// + /// The popup menu in which the options should be displayed. + /// The context menu position. + /// The position of the raycast hit. + /// The graph element to get the options for + /// The game object that the graph element is attached to + /// Actions to be append at the end of the entries. + /// Options available for the given graph element + /// Thrown if the graph element is neither a node nor an edge + private static IEnumerable GetApplicableOptions(PopupMenu popupMenu, Vector3 position, + Vector3 raycastHitPosition, GraphElement graphElement, GameObject gameObject = null, + IEnumerable appendActions = null) + { + IEnumerable options + = GetCommonOptions(popupMenu, position, raycastHitPosition, graphElement, gameObject, appendActions); return options.Concat(graphElement switch { - Node node => GetNodeOptions(node, gameObject), - Edge edge => GetEdgeOptions(edge, gameObject), + Node node => GetNodeOptions(popupMenu, position, raycastHitPosition, node, gameObject, appendActions), + Edge edge => GetEdgeOptions(popupMenu, position, raycastHitPosition, edge, gameObject, appendActions), _ => throw new ArgumentOutOfRangeException() }); } @@ -78,51 +291,103 @@ public static IEnumerable GetApplicableOptions(GraphElement gra /// /// Returns the common options available for all graph elements. /// + /// The popup menu in which the options should be displayed. + /// The position to be displayed the popup menu. + /// The position of the raycast hit. /// The graph element to get the options for /// The game object that the graph element is attached to + /// Actions to be appended at the end of the entries. /// Common options available for all graph elements - private static IEnumerable GetCommonOptions(GraphElement graphElement, GameObject gameObject = null) + private static IEnumerable GetCommonOptions(PopupMenu popupMenu, Vector3 position, + Vector3 raycastHitPosition, GraphElement graphElement, GameObject gameObject = null, + IEnumerable appendActions = null) { - IList actions = new List + string name = graphElement.ID; + string target, source = target = null; + if (graphElement is Node node + && !string.IsNullOrEmpty(node.SourceName)) + { + name = node.SourceName; + } + if (graphElement is Edge edge) + { + name = edge.Type; + source = edge.Source.SourceName ?? edge.Source.ID; + target = edge.Target.SourceName ?? edge.Target.ID; + } + IList entries = new List { - // TODO (#665): Ask for confirmation or allow undo. - new("Delete", DeleteElement, Icons.Trash), - // TODO (#666): Better properties view - new("Properties", ShowProperties, Icons.Info), - new("Show Metrics", ShowMetrics, Icons.Info), + new PopupMenuHeading(name, Priority: int.MaxValue) }; - - if (gameObject != null) + if (source != null && target != null) { - actions.Add(new("Show in City", Highlight, Icons.LightBulb)); + entries.Add(new PopupMenuHeading("Source: " + source, Priority: int.MaxValue)); + entries.Add(new PopupMenuHeading("Target: " + target, Priority: int.MaxValue)); } + entries.Add(new PopupMenuAction("Delete", DeleteElement, Icons.Trash, Priority: 0)); - if (graphElement.Filename != null) + entries.Add(new PopupMenuActionDoubleIcon("Inspect", () => { - actions.Add(new("Show Code", ShowCode, Icons.Code)); - if (gameObject.ContainingCity() != null) + List subMenuEntries = new() + { + new PopupMenuAction("Inspect", () => + { + ProvideParentMenuActions(popupMenu, position, raycastHitPosition, graphElement, gameObject, appendActions); + }, + Icons.ArrowLeft, CloseAfterClick: false), + new PopupMenuAction("Properties", ShowProperties, Icons.Info), + new PopupMenuAction("Show Metrics", ShowMetrics, Icons.Info), + }; + if (gameObject != null) { - actions.Add(new("Show Code Diff", ShowDiffCode, Icons.Code)); + subMenuEntries.Add(new PopupMenuAction("Show in City", Highlight, Icons.LightBulb)); } - } - return actions; + if (graphElement.Filename != null) + { + subMenuEntries.Add(new PopupMenuAction("Show Code", ShowCode, Icons.Code)); + if (gameObject.ContainingCity() != null) + { + subMenuEntries.Add(new PopupMenuAction("Show Code Diff", ShowDiffCode, Icons.Code)); + } + } + subMenuEntries.AddRange(graphElement switch + { + Node node => GetNodeShowOptions(node, gameObject, appendActions != null), + Edge edge => GetEdgeShowOptions(edge, gameObject), + _ => throw new ArgumentOutOfRangeException() + }); + UpdateEntries(popupMenu, position, subMenuEntries); + + }, Icons.Info, Icons.ArrowRight, CloseAfterClick: false, Priority: 1)); + + return entries; void DeleteElement() { + if (graphElement is Node node && node.IsRoot()) + { + ShowNotification.Warn("Forbidden!", "You can't delete a root node."); + return; + } if (gameObject != null) { - GameElementDeleter.Delete(gameObject); + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.Delete); + DeleteAction action = (DeleteAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject); + ExcecutePreviousActionAsync(action, previousAction).Forget(); } else { - graphElement.ItsGraph.RemoveElement(graphElement); + ConfirmDialogMenu confirm = new($"Do you really want to delete the element {graphElement.ID}?\r\nThis action cannot be undone."); + confirm.ExecuteAfterConfirmAsync(() => graphElement.ItsGraph.RemoveElement(graphElement)).Forget(); } } void ShowProperties() { - ShowNotification.Info("Node Properties", graphElement.ToString(), log: false); + ActivateWindow(CreatePropertyWindow(gameObject.MustGetComponent())); } void ShowMetrics() @@ -155,104 +420,75 @@ void Highlight() } /// - /// Activates the tree window for the given graph element and returns it. + /// Provides the actions of the main menu and takes into account any appended actions. /// - /// The graph element to activate the tree window for - /// The transform of the game object that the graph element is attached to - /// The title of the tree window to be used. Should only be set if this is not supposed - /// to be the main tree window. - /// The activated tree window - private static TreeWindow ActivateTreeWindow(GraphElement graphElement, Transform transform, string title = null) + /// The popup menu in which the options should be displayed. + /// The position to be displayed the popup menu. + /// The position of the raycast hit. + /// The graph element to get the options for + /// The game object that the graph element is attached to + /// Actions to be appended at the end of the entries. + private static void ProvideParentMenuActions(PopupMenu popupMenu, Vector3 position, + Vector3 raycastHitPosition, GraphElement graphElement, GameObject gameObject = null, + IEnumerable appendActions = null) { - WindowSpace manager = WindowSpaceManager.ManagerInstance[WindowSpaceManager.LocalPlayer]; - TreeWindow openWindow = manager.Windows.OfType().FirstOrDefault(x => x.Graph == graphElement.ItsGraph && (title == null || x.Title == title)); - if (openWindow == null) - { - // Window is not open yet, so we create it. - GameObject city = SceneQueries.GetCodeCity(transform).gameObject; - openWindow = city.AddComponent(); - openWindow.Graph = graphElement.ItsGraph; - if (title != null) + if (appendActions != null) { - openWindow.Title = title; + List actions = new(GetApplicableOptions(popupMenu, position, raycastHitPosition, + graphElement, gameObject, appendActions) + .OfType() + .Where(x => !x.Name.Contains("TreeWindow"))); + actions.AddRange(appendActions); + UpdateEntries(popupMenu, position, actions); + } + else + { + UpdateEntries(popupMenu, position, GetApplicableOptions(popupMenu, position, raycastHitPosition, + graphElement, gameObject)); } - manager.AddWindow(openWindow); - } - manager.ActiveWindow = openWindow; - return openWindow; - } - - /// - /// Returns a showing the attributes of . - /// - /// The graph element to activate the metric window for - /// The object showing the attributes of the specified graph element. - private static MetricWindow CreateMetricWindow(GraphElementRef graphElementRef) - { - // Create new window for active selection, or use existing one - if (!graphElementRef.TryGetComponent(out MetricWindow metricMenu)) - { - metricMenu = graphElementRef.gameObject.AddComponent(); - metricMenu.Title = "Metrics for " + graphElementRef.Elem.ToShortString(); - metricMenu.GraphElement = graphElementRef.Elem; - } - return metricMenu; - } - - /// - /// Activates the given window, that is, adds it to the window space and makes it the active window. - /// - /// The window to activate - private static void ActivateWindow(BaseWindow window) - { - WindowSpace manager = WindowSpaceManager.ManagerInstance[WindowSpaceManager.LocalPlayer]; - if (!manager.Windows.Contains(window)) - { - manager.AddWindow(window); - } - manager.ActiveWindow = window; } /// - /// Returns the options available for the given node. + /// Returns the show options available for the given node. /// - /// The node to get the options for + /// The node to get the show options for /// The game object that the node is attached to - /// Options available for the given node - private static IEnumerable GetNodeOptions(Node node, GameObject gameObject) + /// Whether the popup menu was opened via tree view. + /// Show options available for the given node + private static IEnumerable GetNodeShowOptions(Node node, GameObject gameObject, bool openViaTreeView) { - IList actions = new List + List actions = new(); + if (!openViaTreeView) { - new("Reveal in TreeView", RevealInTreeView, Icons.TreeView), - }; - + actions.Add(new PopupMenuAction("Reveal in TreeView", RevealInTreeView, Icons.TreeView)); + } if (node.OutgoingsOfType(LSP.Reference).Any()) { - actions.Add(new("Show References", () => ShowTargets(LSP.Reference, false).Forget(), Icons.IncomingEdge)); + actions.Add(new PopupMenuAction("Show References", () => ShowTargets(LSP.Reference, false).Forget(), Icons.IncomingEdge)); } if (node.OutgoingsOfType(LSP.Declaration).Any()) { - actions.Add(new("Show Declaration", () => ShowTargets(LSP.Declaration).Forget(), Icons.OutgoingEdge)); + actions.Add(new PopupMenuAction("Show Declaration", () => ShowTargets(LSP.Declaration).Forget(), Icons.OutgoingEdge)); } if (node.OutgoingsOfType(LSP.Definition).Any()) { - actions.Add(new("Show Definition", () => ShowTargets(LSP.Definition).Forget(), Icons.OutgoingEdge)); + actions.Add(new PopupMenuAction("Show Definition", () => ShowTargets(LSP.Definition).Forget(), Icons.OutgoingEdge)); } if (node.OutgoingsOfType(LSP.Extend).Any()) { - actions.Add(new("Show Supertype", () => ShowTargets(LSP.Extend).Forget(), Icons.OutgoingEdge)); + actions.Add(new PopupMenuAction("Show Supertype", () => ShowTargets(LSP.Extend).Forget(), Icons.OutgoingEdge)); } if (node.OutgoingsOfType(LSP.Call).Any()) { - actions.Add(new("Show Outgoing Calls", () => ShowTargets(LSP.Call).Forget(), Icons.OutgoingEdge)); + actions.Add(new PopupMenuAction("Show Outgoing Calls", () => ShowTargets(LSP.Call).Forget(), Icons.OutgoingEdge)); } if (node.OutgoingsOfType(LSP.OfType).Any()) { - actions.Add(new("Show Type", () => ShowTargets(LSP.OfType).Forget(), 'T')); + actions.Add(new PopupMenuAction("Show Type", () => ShowTargets(LSP.OfType).Forget(), 'T')); } - return actions; + void RevealInTreeView() { ActivateTreeWindow(node, gameObject.transform).RevealElementAsync(node).Forget(); @@ -285,30 +521,133 @@ async UniTaskVoid ShowTargets(string kind, bool outgoings = true) } /// - /// Returns the options available for the given edge. + /// Returns the options available for the given node. /// - /// The edge to get the options for - /// The game object that the edge is attached to - /// Options available for the given edge - private static IEnumerable GetEdgeOptions(Edge edge, GameObject gameObject) + /// The popup menu in which the options should be displayed. + /// The position to be displayed the popup menu. + /// The position of the raycast hit. + /// The node to get the options for + /// The game object that the node is attached to + /// Actions to be appended at the end of the entries. + /// Options available for the given node + private static IEnumerable GetNodeOptions(PopupMenu popupMenu, Vector3 position, Vector3 raycastHitPosition, + Node node, GameObject gameObject, IEnumerable appendActions) { - IList actions = new List + IList actions = new List(); + + if (appendActions == null) { - new("Show at Source (TreeView)", RevealAtSource, Icons.TreeView), - new("Show at Target (TreeView)", RevealAtTarget, Icons.TreeView), - }; + actions.Add(new PopupMenuAction("Edit Node", EditNode, Icons.PenToSquare, Priority: 1)); + actions.Add(new PopupMenuAction("Move", MoveNode, Icons.Move, Priority: 5)); + actions.Add(new PopupMenuAction("New Edge", NewEdge, Icons.Edge, Priority: 2)); + actions.Add(new PopupMenuAction("New Node", NewNode, '+', Priority: 3)); - if (edge.Type == "Clone") + if (gameObject != null) + { + VisualNodeAttributes gameNodeAttributes = gameObject.ContainingCity().NodeTypes[node.Type]; + if (gameNodeAttributes.AllowManualNodeManipulation) + { + actions.Add(new PopupMenuAction("Rotate", RotateNode, Icons.Rotate, Priority: 4)); + actions.Add(new PopupMenuAction("Resize Node", ResizeNode, Icons.Resize)); + actions.Add(new PopupMenuAction("Scale Node", ScaleNode, Icons.Scale)); + } + } + } + + return node.IsRoot() ? new List() { } : + new List() { CreateSubMenu(popupMenu, position, raycastHitPosition, + "Node Options", Icons.Node, actions, node, gameObject, 2, appendActions) }; + + void MoveNode() { - actions.Add(new("Show Unified Diff", ShowUnifiedDiff, Icons.Compare)); + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.Move); + UpdatePlayerMenu(); + MoveAction action = (MoveAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject, raycastHitPosition); + ExcecutePreviousActionAsync(action, previousAction).Forget(); } - if (edge.IsInImplementation() && ReflexionGraph.IsDivergent(edge)) + void RotateNode() { - actions.Add(new("Accept Divergence", AcceptDivergence, Icons.Checkmark)); + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.Rotate); + UpdatePlayerMenu(); + RotateAction action = (RotateAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject); + ExcecutePreviousActionAsync(action, previousAction).Forget(); } - return actions; + void NewNode() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.NewNode); + AddNodeAction action = (AddNodeAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject, raycastHitPosition); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + + void NewEdge() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.NewEdge); + UpdatePlayerMenu(); + AddEdgeAction action = (AddEdgeAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + + void EditNode() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.EditNode); + UpdatePlayerMenu(); + EditNodeAction action = (EditNodeAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(node); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + + void ResizeNode() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.ResizeNode); + UpdatePlayerMenu(); + ResizeNodeAction action = (ResizeNodeAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + + void ScaleNode() + { + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.ScaleNode); + UpdatePlayerMenu(); + ScaleNodeAction action = (ScaleNodeAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(gameObject); + ExcecutePreviousActionAsync(action, previousAction).Forget(); + } + } + + /// + /// Returns the show options available for the given edge. + /// + /// The edge to get the show options for + /// The game object that the edge is attached to + /// Show options available for the given edge + private static IEnumerable GetEdgeShowOptions(Edge edge, GameObject gameObject) + { + List entries = new() { + new PopupMenuAction("Show at Source (TreeView)", RevealAtSource, Icons.TreeView), + new PopupMenuAction("Show at Target (TreeView)", RevealAtTarget, Icons.TreeView) + }; + + if (edge.Type == "Clone") + { + entries.Add(new PopupMenuAction("Show Unified Diff", ShowUnifiedDiff, Icons.Compare)); + } + + return entries; + void RevealAtSource() { @@ -325,10 +664,185 @@ void ShowUnifiedDiff() ActivateWindow(ShowCodeAction.ShowUnifiedDiff(gameObject.MustGetComponent())); } + } + + /// + /// Returns the options available for the given edge. + /// + /// The popup menu in which the options should be displayed. + /// The position to be displayed the popup menu. + /// The position of the raycast hit. + /// The edge to get the options for + /// The game object that the edge is attached to + /// Options to be append at the end of the entries. + /// Options available for the given edge + private static IEnumerable GetEdgeOptions + (PopupMenu popupMenu, + Vector3 position, + Vector3 raycastHitPosition, + Edge edge, + GameObject gameObject, + IEnumerable appendActions = null) + { + IList actions = new List(); + + if (edge.IsInImplementation() && ReflexionGraph.IsDivergent(edge)) + { + actions.Add(new PopupMenuAction("Accept Divergence", AcceptDivergence, Icons.Checkmark)); + } + + List entries = new(); + if (actions.Count > 0) + { + entries.Add(CreateSubMenu(popupMenu, position, raycastHitPosition, + "Edge Options", Icons.Node, actions, edge, gameObject, 2, appendActions)); + } + return entries; + void AcceptDivergence() { - AcceptDivergenceAction.CreateConvergentEdge(edge); + ActionStateType previousAction = GlobalActionHistory.Current(); + GlobalActionHistory.Execute(ActionStateTypes.AcceptDivergence); + AcceptDivergenceAction action = (AcceptDivergenceAction)GlobalActionHistory.CurrentAction(); + action.ContextMenuExecution(edge); + ExcecutePreviousActionAsync(action, previousAction).Forget(); } } + #endregion + + /// + /// Activates the tree window for the given graph element and returns it. + /// + /// The graph element to activate the tree window for + /// The transform of the game object that the graph element is attached to + /// The title of the tree window to be used. Should only be set if this is not supposed + /// to be the main tree window. + /// The activated tree window + private static TreeWindow ActivateTreeWindow(GraphElement graphElement, Transform transform, string title = null) + { + WindowSpace manager = WindowSpaceManager.ManagerInstance[WindowSpaceManager.LocalPlayer]; + TreeWindow openWindow = manager.Windows.OfType() + .FirstOrDefault(x => x.Graph == graphElement.ItsGraph && (title == null || x.Title == title)); + + if (openWindow == null) + { + // Window is not open yet, so we create it. + GameObject city = SceneQueries.GetCodeCity(transform).gameObject; + openWindow = city.AddComponent(); + openWindow.Graph = graphElement.ItsGraph; + if (title != null) + { + openWindow.Title = title; + } + manager.AddWindow(openWindow); + } + manager.ActiveWindow = openWindow; + return openWindow; + } + + /// + /// Returns a showing the attributes of . + /// + /// The graph element to activate the metric window for + /// The object showing the attributes of the specified graph element. + private static MetricWindow CreateMetricWindow(GraphElementRef graphElementRef) + { + // Create new window for active selection, or use existing one + if (!graphElementRef.TryGetComponent(out MetricWindow metricMenu)) + { + metricMenu = graphElementRef.gameObject.AddComponent(); + metricMenu.Title = "Metrics for " + graphElementRef.Elem.ToShortString(); + metricMenu.GraphElement = graphElementRef.Elem; + } + return metricMenu; + } + + /// + /// Returns a showing the attributes of . + /// + /// The graph element to activate the property window for + /// The object showing the attributes of the specified graph element. + private static PropertyWindow CreatePropertyWindow(GraphElementRef graphElementRef) + { + // Create new window for active selection, or use existing one + if (!graphElementRef.TryGetComponent(out PropertyWindow propertyMenu)) + { + propertyMenu = graphElementRef.gameObject.AddComponent(); + propertyMenu.Title = "Properties for " + graphElementRef.Elem.ToShortString(); + propertyMenu.GraphElement = graphElementRef.Elem; + } + return propertyMenu; + } + + /// + /// Activates the given window, that is, adds it to the window space and makes it the active window. + /// + /// The window to activate + private static void ActivateWindow(BaseWindow window) + { + WindowSpace manager = WindowSpaceManager.ManagerInstance[WindowSpaceManager.LocalPlayer]; + if (!manager.Windows.Contains(window)) + { + manager.AddWindow(window); + } + manager.ActiveWindow = window; + } + + /// + /// Creates a sub menu for the context menu. + /// + /// The popup menu in which the options should be displayed. + /// The position to be displayed in the popup menu. + /// The position of the raycast hit. + /// The name for the sub menu. + /// The icon for the sub menu. + /// A list of the actions which should be displayed in the sub menu. + /// The graph element to get the options for + /// The game object that the graph element is attached to + /// The priority for this sub menu. + /// Actions to be append at the end of the entries. + /// The created sub menu. + private static PopupMenuActionDoubleIcon CreateSubMenu(PopupMenu popupMenu, Vector3 position, + Vector3 raycastHitPosition, string name, char icon, IEnumerable actions, + GraphElement graphElement, GameObject gameObject = null, int priority = 0, + IEnumerable appendActions = null) + { + return new(name, () => + { + List entries = new() + { + new PopupMenuAction(name, () => + { + ProvideParentMenuActions(popupMenu, position, raycastHitPosition, graphElement, gameObject, appendActions); + }, + Icons.ArrowLeft, CloseAfterClick: false, Priority: int.MaxValue) + }; + entries.AddRange(actions); + UpdateEntries(popupMenu, position, entries); + }, icon, Icons.ArrowRight, CloseAfterClick: false, priority); + } + + /// + /// Ensures that the previous action is executed again after the current action has + /// been fully completed (). + /// Additionally, the is updated. + /// + /// The current action which was executed via context menu. + /// The previously executed action to be re-executed. + private static async UniTask ExcecutePreviousActionAsync(IReversibleAction action, ActionStateType previousAction) + { + await UniTask.WaitUntil(() => action.CurrentProgress() == IReversibleAction.Progress.Completed); + GlobalActionHistory.Execute(previousAction); + UpdatePlayerMenu(); + } + + /// + /// Updates the current active entry in the . + /// + private static void UpdatePlayerMenu() + { + LocalPlayer.TryGetPlayerMenu(out PlayerMenu menu); + menu.UpdateActiveEntry(); + } } } diff --git a/Assets/SEE/Controls/Actions/DeleteAction.cs b/Assets/SEE/Controls/Actions/DeleteAction.cs index 9c5a120a07..d4a49b7fd3 100644 --- a/Assets/SEE/Controls/Actions/DeleteAction.cs +++ b/Assets/SEE/Controls/Actions/DeleteAction.cs @@ -83,10 +83,10 @@ public override void Stop() } /// - /// The graph element (a game object representing a node or edge) that was - /// hit by the user for deletion. Set in . + /// The graph elements (game objects, each representing a node or edge) that were + /// chosen by the user for deletion. /// - private GameObject hitGraphElement; + private List hitGraphElements = new(); /// /// Contains all implicitly deleted nodes and edges as a consequence of the deletion @@ -98,9 +98,6 @@ public override void Stop() /// are deleted and contained in this set. This set will always include the /// explicitly selected node to be deleted. /// - /// The will always be included in this set - /// unless it is null. - /// /// Note that we will not actually destroy the deleted objects for the time /// being to be able to revert the deletion. Instead the objects will simply be set /// to inactive so that they are no longer visible and findable. They will @@ -120,14 +117,12 @@ public override bool Update() && Raycasting.RaycastGraphElement(out RaycastHit raycastHit, out GraphElementRef _) != HitGraphElement.None) { // the hit object is the one to be deleted - hitGraphElement = raycastHit.collider.gameObject; - Assert.IsTrue(hitGraphElement.HasNodeRef() || hitGraphElement.HasEdgeRef()); - InteractableObject.UnselectAll(true); - (_, deletedGameObjects) = GameElementDeleter.Delete(hitGraphElement); - new DeleteNetAction(hitGraphElement.name).Execute(); - CurrentState = IReversibleAction.Progress.Completed; - AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.DropSound); - return true; // the selected objects are deleted and this action is done now + hitGraphElements.Add(raycastHit.collider.gameObject); + return Delete(); // the selected objects are deleted and this action is done now + } + else if (ExecuteViaContextMenu) + { + return Delete(); } else { @@ -135,6 +130,52 @@ public override bool Update() } } + /// + /// Executes the deletion. + /// + /// true if the deletion can be executed. + private bool Delete() + { + deletedGameObjects = new HashSet(); + InteractableObject.UnselectAll(true); + foreach (GameObject go in hitGraphElements) + { + if (!go.HasNodeRef() && !go.HasEdgeRef() + || go.HasNodeRef() && go.IsRoot()) + { + continue; + } + (_, ISet deleted) = GameElementDeleter.Delete(go); + deletedGameObjects.UnionWith(deleted); + } + CurrentState = IReversibleAction.Progress.Completed; + AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.DropSound); + return true; + } + + /// + /// Used to execute the from the context menu. + /// It sets the object to be deleted and ensures that the method + /// performs the execution via context menu. + /// + /// The object to be deleted. + public void ContextMenuExecution(GameObject toDelete) + { + ContextMenuExecution(new List { toDelete }); + } + + /// + /// Used to execute the from the multiselection context menu. + /// It sets the objects to be deleted and ensures that the method + /// performs the execution via context menu. + /// + /// The objects to be deleted. + public void ContextMenuExecution(IEnumerable toDelete) + { + ExecuteViaContextMenu = true; + hitGraphElements = toDelete.ToList(); + } + /// /// Undoes this DeleteAction. /// @@ -151,8 +192,17 @@ public override void Undo() public override void Redo() { base.Redo(); - GameElementDeleter.Delete(hitGraphElement); - new DeleteNetAction(hitGraphElement.name).Execute(); + foreach (GameObject go in hitGraphElements) + { + if (go.IsRoot()) + { + continue; + } + new DeleteNetAction(go.name).Execute(); +#pragma warning disable VSTHRD110 + GameElementDeleter.Delete(go); +#pragma warning restore VSTHRD110 + } } /// diff --git a/Assets/SEE/Controls/Actions/DrawAction.cs b/Assets/SEE/Controls/Actions/DrawAction.cs deleted file mode 100644 index fcd0dfce83..0000000000 --- a/Assets/SEE/Controls/Actions/DrawAction.cs +++ /dev/null @@ -1,197 +0,0 @@ -using SEE.Game; -using SEE.GO; -using SEE.Utils; -using System; -using System.Collections.Generic; -using UnityEngine; -using SEE.Audio; -using SEE.Utils.History; - -namespace SEE.Controls.Actions -{ - /// - /// Allows to create drawings by the mouse cursor. - /// It serves as an example for a continuous action that modifies the - /// scene while active. - /// - internal class DrawAction : AbstractPlayerAction - { - /// - /// A new instance of . - /// See . - /// - /// new instance of - public static IReversibleAction CreateReversibleAction() - { - return new DrawAction(); - } - - /// - /// A new instance of . - /// See . - /// - /// new instance of - public override IReversibleAction NewInstance() - { - return CreateReversibleAction(); - } - - /// - /// The material for all lines drawn by this action. Will be generated randomly - /// (see the static constructor). - /// - private static readonly Material material; - - /// - /// The object holding the line renderer. - /// - private GameObject line; - - /// - /// The renderer used to draw the line. - /// - private LineRenderer renderer; - - /// - /// The positions of the line in world space. - /// - private Vector3[] positions; - - /// - /// Static constructor initializing . - /// - static DrawAction() - { - // A random color. - Color color = UnityEngine.Random.ColorHSV(); - // A range of exactly that single random color. - ColorRange colorRange = new ColorRange(color, color, 1); - // The materials factory for exactly that single random color. - Materials materials = new Materials(Materials.ShaderType.PortalFree, colorRange); - // The material for exactly that single random color. - material = materials.Get(0, 0); - } - - /// - /// Initializes , , and . - /// See . - /// - public override void Awake() - { - base.Awake(); - positions = new Vector3[0]; - } - - /// - /// Creates and adds to it. - /// The matrial for the line will be . - /// Sets the attributes of the line. Does not actually draw anything. - /// - private void SetUpRenderer() - { - line = new GameObject("line"); - renderer = line.AddComponent(); - renderer.sharedMaterial = material; // all lines share the same material - renderer.startWidth = 0.01f; - renderer.endWidth = renderer.startWidth; - renderer.useWorldSpace = true; - renderer.positionCount = positions.Length; - } - - /// - /// Continues the line at the point of the mouse position and draws it. - /// See . - /// - public override bool Update() - { - if (!Raycasting.IsMouseOverGUI()) - { - if (Input.GetMouseButtonDown(0) || Input.GetMouseButton(0)) - { - // We create the line on demand so that there is no left-over - // when the drawing action has never actually started to draw anything. - if (line == null) - { - SetUpRenderer(); - } - // FIXME: This would needed to be adjusted to VR and AR. - // The position at which to continue the line. - Vector3 newPosition = Input.mousePosition; - newPosition.z = 1.0f; - newPosition = Camera.main.ScreenToWorldPoint(newPosition); - - // Add newPosition to the line renderer. - Vector3[] newPositions = new Vector3[positions.Length + 1]; - Array.Copy(sourceArray: positions, destinationArray: newPositions, length: positions.Length); - newPositions[newPositions.Length - 1] = newPosition; - positions = newPositions; - - DrawLine(); - // The line has been continued so this action has had a visible effect. - CurrentState = IReversibleAction.Progress.Completed; - } - if (Input.GetMouseButtonDown(0)) - { - AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.ScribbleSound); - } - // The action is considered complete if the mouse button is no longer pressed. - return Input.GetMouseButtonUp(0); - } - return false; - } - - /// - /// Draws the line given the . - /// - private void DrawLine() - { - renderer.positionCount = positions.Length; - renderer.SetPositions(positions); - } - - /// - /// Destroys the drawn line. - /// See . - /// - public override void Undo() - { - base.Undo(); // required to set properly. - Destroyer.Destroy(line); - line = null; - renderer = null; - } - - /// - /// Redraws the drawn line (setting up and adds - /// before that). - /// See . - /// - public override void Redo() - { - base.Redo(); // required to set properly. - SetUpRenderer(); - DrawLine(); - } - - /// - /// Returns the of this action. - /// - /// - public override ActionStateType GetActionStateType() - { - return ActionStateTypes.Draw; - } - - /// - /// The set of IDs of all gameObjects changed by this action. - /// - /// Because this action does not actually change any game object, - /// an empty set is always returned. - /// - /// an empty set - public override HashSet GetChangedObjects() - { - return new HashSet(); - } - } -} diff --git a/Assets/SEE/Controls/Actions/EditNodeAction.cs b/Assets/SEE/Controls/Actions/EditNodeAction.cs index 089f755b70..7ebea455e1 100644 --- a/Assets/SEE/Controls/Actions/EditNodeAction.cs +++ b/Assets/SEE/Controls/Actions/EditNodeAction.cs @@ -7,6 +7,8 @@ using SEE.Utils; using UnityEngine; using SEE.Utils.History; +using SEE.Game.SceneManipulation; +using SEE.UI.Notification; namespace SEE.Controls.Actions { @@ -99,9 +101,16 @@ public override bool Update() GameObject editedNode = raycastHit.collider.gameObject; if (editedNode.TryGetNode(out Node node)) { - progress = ProgressState.WaitingForInput; - memento = new Memento(node); - OpenDialog(); + if (!node.IsRoot()) + { + progress = ProgressState.WaitingForInput; + memento = new Memento(node); + OpenDialog(); + } + else + { + ShowNotification.Warn("Root node is readonly", "You cannot edit the root node."); + } } else { @@ -126,11 +135,24 @@ public override bool Update() break; default: - throw new NotImplementedException("Unhandled case."); + throw new NotImplementedException($"Unhandled case {nameof(progress)}."); } return result; } + /// + /// Used to execute the from the context menu. + /// Opens the edit dialog for the + /// and ensures that the method performs the execution via context menu. + /// + /// The node to be edit. + public void ContextMenuExecution(Node node) + { + progress = ProgressState.WaitingForInput; + memento = new Memento(node); + OpenDialog(); + } + /// /// Sends an EditNodeNetAction to all clients with the given 's /// ID, SourceName and Type. @@ -147,8 +169,8 @@ private static void NotifyClients(Node node) public override void Undo() { base.Undo(); - memento.Node.SourceName = memento.OriginalName; - memento.Node.Type = memento.OriginalType; + GameNodeEditor.ChangeName(memento.Node, memento.OriginalName); + GameNodeEditor.ChangeType(memento.Node, memento.OriginalType); NotifyClients(memento.Node); } @@ -158,8 +180,8 @@ public override void Undo() public override void Redo() { base.Redo(); - memento.Node.SourceName = memento.NewName; - memento.Node.Type = memento.NewType; + GameNodeEditor.ChangeName(memento.Node, memento.NewName); + GameNodeEditor.ChangeType(memento.Node, memento.NewType); NotifyClients(memento.Node); } diff --git a/Assets/SEE/Controls/Actions/GlobalActionHistory.cs b/Assets/SEE/Controls/Actions/GlobalActionHistory.cs index 40540af29d..3b6bf6fe77 100644 --- a/Assets/SEE/Controls/Actions/GlobalActionHistory.cs +++ b/Assets/SEE/Controls/Actions/GlobalActionHistory.cs @@ -1,5 +1,4 @@ -using SEE.Utils; -using SEE.Utils.History; +using SEE.Utils.History; using static SEE.Utils.History.ActionHistory; namespace SEE.Controls.Actions @@ -13,7 +12,7 @@ public static class GlobalActionHistory /// /// The history of actions. /// - private static readonly ActionHistory history = new ActionHistory(); + private static readonly ActionHistory history = new(); /// /// Executes the currently active action (if there is any). @@ -95,6 +94,15 @@ public static ActionStateType Current() return history.CurrentAction?.GetActionStateType(); } + /// + /// Gets the currently executed action. + /// + /// The currently executed action. + public static IReversibleAction CurrentAction() + { + return history.CurrentAction; + } + /// /// True if the action history is empty. /// diff --git a/Assets/SEE/Controls/Actions/MoveAction.cs b/Assets/SEE/Controls/Actions/MoveAction.cs index 919b1cf2db..882b0de9be 100644 --- a/Assets/SEE/Controls/Actions/MoveAction.cs +++ b/Assets/SEE/Controls/Actions/MoveAction.cs @@ -1,17 +1,21 @@ using System; using System.Collections.Generic; using SEE.Audio; +using SEE.Controls.Interactables; +using SEE.DataModel.DG; using SEE.Game; using SEE.Game.City; +using SEE.Game.Drawable.ActionHelpers; using SEE.Game.SceneManipulation; -using SEE.UI.Notification; using SEE.GO; using SEE.Net.Actions; using SEE.Tools.ReflexionAnalysis; +using SEE.UI.Notification; using SEE.Utils; -using UnityEngine; -using Node = SEE.DataModel.DG.Node; using SEE.Utils.History; +using UnityEngine; +using UnityEngine.EventSystems; + namespace SEE.Controls.Actions { @@ -20,6 +24,23 @@ namespace SEE.Controls.Actions /// internal class MoveAction : AbstractPlayerAction { + /// + /// The currently grabbed object if any. + /// + private GrabbedObject grabbedObject; + + /// + /// The object to move which was selected via context menu. + /// + private GameObject contextMenuObjectToMove; + + /// + /// The offset of the cursor to the pivot of . + /// + private Vector3 cursorOffset = Vector3.zero; + + #region ReversibleAction + /// /// Returns a new instance of . /// @@ -53,6 +74,141 @@ public override ActionStateType GetActionStateType() return ActionStateTypes.Move; } + /// + /// Reacts to the user interactions. An object can be grabbed and moved + /// around. If it is put onto another node, it will be re-parented onto this + /// node. If we are operating in a , re-parenting + /// may be a mapping of an implementation node onto an architecture node + /// or a hierarchical re-parenting. If we are operating in a different kind + /// of city, re-parenting is always hierarchically interpreted. A hierarchical + /// re-parenting means that the moved node becomes a child of the target node + /// both in the game-node hierarchy as well as in the underlying graph. + /// . + /// + /// true if completed + public override bool Update() + { + if (EventSystem.current.IsPointerOverGameObject()) + { + // User interacts with UI element + return false; + } + bool mouseHeldDown = Queries.LeftMouseInteraction(); + if (!grabbedObject.IsGrabbed) // grab object + { + if (Queries.LeftMouseDown() && !ExecuteViaContextMenu) + { + // User starts dragging the currently hovered object. + InteractableObject hoveredObject = InteractableObject.HoveredObjectWithWorldFlag; + if (hoveredObject == null) + { + return false; + } + + if (Raycasting.RaycastGraphElement(out RaycastHit grabbedObjectHit, out GraphElementRef _) + == HitGraphElement.Node) + { + cursorOffset = grabbedObjectHit.point - hoveredObject.transform.position; + } + + // An object to be grabbed must be representing a node that is not the root. + if (hoveredObject.gameObject.TryGetNode(out Node node) && !node.IsRoot()) + { + grabbedObject.Grab(hoveredObject.gameObject); + AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.PickupSound, hoveredObject.gameObject); + CurrentState = IReversibleAction.Progress.InProgress; + } + else + { + return false; + } + + } + else if (ExecuteViaContextMenu && !mouseHeldDown) + { + // User starts dragging object selected via context menu. + // Override the initial cursorOffset based on new mouse position to reduce jump + if (contextMenuObjectToMove.TryGetNodeRef(out NodeRef nodeRef) + && Raycasting.RaycastLowestNode(out RaycastHit? targetObjectHit, out Node _, nodeRef)) + { + // Calculate position on object and close to the cursor + Vector3 objectSize = contextMenuObjectToMove.WorldSpaceSize(); + Vector3 objectPosition = contextMenuObjectToMove.transform.position; + Vector3 anchorPosition = targetObjectHit.Value.point; + anchorPosition.x = Mathf.Clamp(anchorPosition.x, objectPosition.x - 0.5f * objectSize.x, objectPosition.x + 0.5f * objectSize.x); + anchorPosition.z = Mathf.Clamp(anchorPosition.z, objectPosition.z - 0.5f * objectSize.z, objectPosition.z + 0.5f * objectSize.z); + cursorOffset = anchorPosition - objectPosition; + } + + grabbedObject.Grab(contextMenuObjectToMove); + CurrentState = IReversibleAction.Progress.InProgress; + } + } + else if (mouseHeldDown ^ ExecuteViaContextMenu) // drag grabbed object + { + Raycasting.RaycastLowestNode(out RaycastHit? targetObjectHit, out Node _, grabbedObject.Node); + if (targetObjectHit.HasValue) + { + GameObject newTarget = targetObjectHit.Value.transform.gameObject; + grabbedObject.MoveToTarget(newTarget, targetObjectHit.Value.point - cursorOffset); + // The grabbed node is not yet at its final destination. The user is still moving + // it. We will run a what-if reflexion analysis to give immediate feedback on the + // consequences if the user were putting the grabbed node onto the node the user + // is currently aiming at. + grabbedObject.Reparent(newTarget, true); + } + } + else // end dragging + { + if (grabbedObject.GrabbedGameObject != null) + { + AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.DropSound, grabbedObject.GrabbedGameObject); + } + + bool wasMoved = grabbedObject.UnGrab(); + // Action is finished. + // Prevent instant re-grab if the action was started via context menu and is not completed + ExecuteViaContextMenu = ExecuteViaContextMenu && wasMoved; + CurrentState = wasMoved ? IReversibleAction.Progress.Completed : IReversibleAction.Progress.NoEffect; + return wasMoved; + } + return false; + } + + /// + /// . + /// + public override void Undo() + { + base.Undo(); + grabbedObject.Undo(); + } + + /// + /// . + /// + public override void Redo() + { + base.Redo(); + grabbedObject.Redo(); + } + + #endregion ReversibleAction + + /// + /// Used to execute the from the context menu. + /// It ensures that the method performs the execution via context menu for + /// the selected game object . + /// + /// The object to be moved. + /// The hit position of the object + public void ContextMenuExecution(GameObject objToMove, Vector3 raycastHitPosition) + { + ExecuteViaContextMenu = true; + cursorOffset = raycastHitPosition - objToMove.transform.position; + contextMenuObjectToMove = objToMove; + } + /// /// Data structure to manage the game object that was grabbed. /// Provides also the necessary capability for Undo/Redo. @@ -85,7 +241,6 @@ public void Grab(GameObject gameObject) { GrabbedGameObject = gameObject; originalParent = gameObject.transform.parent; - originalLocalScale = gameObject.transform.localScale; originalWorldPosition = gameObject.transform.position; IsGrabbed = true; if (gameObject.TryGetComponent(out InteractableObject interactableObject)) @@ -111,50 +266,77 @@ public void Grab(GameObject gameObject) } /// - /// The currently grabbed object is considered to be ungrabbed. + /// Ends the move action by making the new position final. + /// The grabbed object will be reset to its original position if placement at the current position is not possible. /// + /// true if the object has been placed, or false if placement has been reset /// thrown if no object is currently /// grabbed - public void UnGrab() + public bool UnGrab() { if (!IsGrabbed || GrabbedGameObject == null) { throw new InvalidOperationException("No object is being grabbed."); } + + bool wasMoved = originalWorldPosition != currentPositionOfGrabbedObject; + if (!CanBePlaced()) + { + // Node does not fit, resetting… + UnReparent(); + wasMoved = false; + } else { - UnmarkAsTarget(); - if (GrabbedGameObject.TryGetComponent(out InteractableObject interactableObject)) - { - interactableObject.SetGrab(grab: false, isInitiator: true) ; - } - ShowLabel.Off(GrabbedGameObject); - IsGrabbed = false; - // Note: We do not set grabbedObject to null because we may need its - // value later for Undo/Redo. + UnHighlightTarget(); + } + + if (GrabbedGameObject.TryGetComponent(out InteractableObject interactableObject)) + { + interactableObject.SetGrab(grab: false, isInitiator: true); } + ShowLabel.Off(GrabbedGameObject); + IsGrabbed = false; + // Note: We do not set grabbedObject to null because we may need its + // value later for Undo/Redo. + + return wasMoved; + } + + /// + /// Checks if can be placed. + /// + /// It can be placed if: + /// + /// fits in the 2D area of , and + /// does not overlap with its new siblings in + /// + /// + /// true if can be placed + public readonly bool CanBePlaced() + { + Vector3 size = GrabbedGameObject.WorldSpaceSize(); + Vector3 parentSize = NewParent.WorldSpaceSize(); + return size.x <= parentSize.x + && size.z <= parentSize.z + && !GrabbedGameObject.OverlapsWithSiblings(); } /// /// Memorizes the new parent of after it was moved. /// Can be the original parent. Relevant for . /// - private GameObject newParent; + internal GameObject NewParent { private set; get; } /// /// The original parent of before it was grabbed. /// private Transform originalParent; - /// - /// The original local scale of before it was grabbed. - /// - private Vector3 originalLocalScale; - /// /// Whether an object has been grabbed. /// - /// true if an object has been grabbed + /// true if an object has been grabbed /// The default value for bool is false, which is exactly /// what we need internal bool IsGrabbed { private set; get; } @@ -162,7 +344,7 @@ public void UnGrab() /// /// The name of the grabbed object if any was grabbed; otherwise the empty string. /// - internal string Name => GrabbedGameObject != null ? GrabbedGameObject.name : string.Empty; + internal readonly string Name => GrabbedGameObject != null ? GrabbedGameObject.name : string.Empty; /// /// The position of the grabbed object in world space. @@ -187,7 +369,7 @@ internal readonly Vector3 Position /// The node reference associated with the grabbed object. May be null if no /// node is associated with the grabbed object. /// - public NodeRef Node => GrabbedGameObject.TryGetNodeRef(out NodeRef result) ? result : null; + public readonly NodeRef Node => GrabbedGameObject.TryGetNodeRef(out NodeRef result) ? result : null; /// /// The original position of when it was grabbed. @@ -207,10 +389,11 @@ internal readonly Vector3 Position /// private readonly void MoveToOrigin() { - if (GrabbedGameObject) + if (GrabbedGameObject == null) { - MoveTo(GrabbedGameObject, originalWorldPosition); + return; } + MoveTo(GrabbedGameObject, originalWorldPosition); } /// @@ -218,61 +401,80 @@ private readonly void MoveToOrigin() /// to its origin via . /// This method will be called for Redo. /// - private readonly void MoveToLastUserRequestedPosition() + private readonly void MoveToNewPosition() { - if (GrabbedGameObject) + if (GrabbedGameObject == null) { - MoveTo(GrabbedGameObject, currentPositionOfGrabbedObject); + return; } + MoveTo(GrabbedGameObject, currentPositionOfGrabbedObject, 1); } /// - /// Moves the grabbed object to in world space - /// immediately, that is, without any animation. + /// Moves the grabbed game object onto at the approximate position + /// of in world space coordinates. + /// The placement is immediate and without any animation. + /// + /// The is adapted so that the grabbed node will appear on top of the + /// . + /// + /// The will be updated to reflect the actual target + /// world-space position after the move operation. + /// + /// The will NOT be reparented to the . + /// /// - /// the position where the grabbed object - /// should be moved in world space - internal void MoveTo(Vector3 targetPosition) + /// the game object to place the grabbed node on + /// the world-space position where the grabbed node should be moved + internal void MoveToTarget(GameObject targetGameObject, Vector3 targetPosition) { - if (GrabbedGameObject) + if (GrabbedGameObject == null) { - currentPositionOfGrabbedObject = targetPosition; - MoveTo(GrabbedGameObject, targetPosition, 0); + return; } + currentPositionOfGrabbedObject = GameNodeMover.GetCoordinatesOn(GrabbedGameObject.WorldSpaceSize(), targetPosition, targetGameObject); + MoveTo(GrabbedGameObject, currentPositionOfGrabbedObject, 0); } #region HitColor /// - /// The game node we have marked as a target of the grabbed and moved node (where it - /// should be put on / mapped onto). May be null if none has been marked. It is saved - /// here because we need to do the unmarking later. + /// The game node we have highlighted as a target of the move action. + /// May be null if none has been marked. + /// It is stored here because we need to remove the highlight later. /// - private GameObject markedGameObject; + private GameObject highlightedTarget; /// - /// Highlights as a target of the grabbed and moved node. + /// Highlights the current target, , visually and removes previous target highlight. /// - /// the target of the grabbed and moved node - private void MarkAsTarget(Transform hitObject) + private void HighlightTarget() { - markedGameObject = hitObject.gameObject; + if (highlightedTarget == NewParent) + { + return; + } + + UnHighlightTarget(); + highlightedTarget = NewParent; + // [Highlight Plus note] Important! If you change the hierarchy of your object // (change its parent or attach it to another object), you need to call effect.Refresh() // to make Highlight Plus update its internal data. - Highlighter.SetHighlight(markedGameObject, true); - new HighlightNetAction(markedGameObject.name, true).Execute(); + Highlighter.SetHighlight(highlightedTarget, true); + new HighlightNetAction(highlightedTarget.name, true).Execute(); } /// - /// Turns off the highlighting of if not null. + /// Removes the highlight of if not null. /// - private void UnmarkAsTarget() + private void UnHighlightTarget() { - if (markedGameObject) + if (highlightedTarget != null) { - Highlighter.SetHighlight(markedGameObject, false); - new HighlightNetAction(markedGameObject.name, false).Execute(); + Highlighter.SetHighlight(highlightedTarget, false); + new HighlightNetAction(highlightedTarget.name, false).Execute(); + highlightedTarget = null; } } @@ -283,18 +485,20 @@ private void UnmarkAsTarget() /// /// The new state of after this call is its inital /// state at the point in time when it was grabbed, i.e. - /// (1) has its - /// (2) has its - /// (3) has its - /// (4) all side effects of re-parenting have been undone (e.g., + /// + /// has its + /// has its + /// all side effects of re-parenting have been undone (e.g., /// the parent of the graph node associated with /// is the graph node associated with ; /// there may be additional side effects of re-parenting, however, - /// triggered by the reflexion analysis; all of these are reverted). - /// + /// triggered by the reflexion analysis; all of these are reverted). + /// + /// + /// /// Important note: Some of these changes do not come into effect immediately. /// They may be delayed by an animation. - /// + /// internal void Undo() { UnReparent(); @@ -303,91 +507,99 @@ internal void Undo() /// /// Reverts . /// + /// /// The new state of after this call is its /// state at the point in time just before was called, i.e. - /// - /// (1) is put on the roof of possibly scaled down to fit - /// at the world-space position - /// (2) has as its game-object parent - /// (4) all side effects of re-parenting have been are in place (e.g., + /// + /// is put on the roof of at the world-space position + /// + /// has as its game-object parent + /// all side effects of re-parenting are applied (e.g., /// the parent of the graph node associated with /// is the graph node associated with /// if both game nodes represent implementation entities; there may be other /// side effects of re-parenting, however, triggered by the reflexion analysis; - /// all of these are in place). - /// + /// all of these are in place). + /// + /// + /// + /// /// Important note: Some of these changes do not come into effect immediately. /// They may be delayed by an animation. - /// + /// internal void Redo() { - MoveToLastUserRequestedPosition(); - Reparent(newParent); + MoveToNewPosition(); + if (NewParent != originalParent) + { + Reparent(NewParent, false, true); + } } /// - /// Moves onto the roof of - /// visually and marks it as target (the previously marked object is unmarked). + /// Reparents the grabbed object to . + /// + /// If the placement , the target node will be highlighted + /// as well as the grabbed node. The color of the grabbed node's outline indicates if a + /// placement is possible at the current position based available space on . + /// /// Also re-parents onto semantically. /// If , the exact semantics of the re-parenting /// is determined by ; /// otherwise by . - /// + /// /// The will be an immediate child of in the /// game-object hierarchy afterwards. /// /// the target node of the re-parenting, i.e., the new parent - internal void Reparent(GameObject target) + /// if true, the new target is considered temporary + /// if true, the method is executed as part of undo or redo + internal void Reparent(GameObject target, bool isProvisional, bool isUnOrRedo = false) { - // target must not be a descendant of grabbedObject - if (!IsDescendant(target, GrabbedGameObject)) + // Note: If target is a descendant of the grabbed node something must be wrong with the raycast! + bool targetChanged = NewParent != target; + NewParent = isUnOrRedo ? NewParent : target; // continue working with target! + + if (isProvisional) { - PutOnAndFit(GrabbedGameObject, target, originalParent.gameObject, originalLocalScale); - UnmarkAsTarget(); - MarkAsTarget(target.transform); - - newParent = target; - // The mapping is only possible if we are in a reflexion city - // and the mapping target is not the root of the graph. - if (withinReflexionCity && !target.IsRoot()) - { - ReflexionMapperSetParent(GrabbedGameObject, target); - } - else + HighlightTarget(); + if (GrabbedGameObject.TryGetComponent(out Outline outline)) { - GameNodeMoverSetParent(GrabbedGameObject, target); + outline.OutlineColor = CanBePlaced() ? Color.green : Color.red; } } - // True if node is a descendant of root in the underlying graph. - static bool IsDescendant(GameObject node, GameObject root) + if (!targetChanged && !isUnOrRedo) { - return node.GetNode().IsDescendantOf(root.GetNode()); + return; + } + + // The mapping is only possible if we are in a reflexion city + // and the mapping target is not the root of the graph. + if (withinReflexionCity && !target.IsRoot()) + { + ReflexionMapperSetParent(GrabbedGameObject, target); + } + else + { + GameNodeMoverSetParent(GrabbedGameObject, target); } } /// /// Reverts the parenting of the , i.e., unmarks the - /// current target and restores original position and scale of . + /// current target and restores original position of . /// If , its explicit architecture mapping will be /// removed; otherwise its will be restored. /// + /// /// This method is the reverse function of . + /// /// internal void UnReparent() { - UnmarkAsTarget(); - if (GrabbedGameObject.transform.parent.gameObject != originalParent.gameObject) - { - if (withinReflexionCity) - { - ReflexionMapperSetParent(GrabbedGameObject, originalParent.gameObject); - } - else - { - GameNodeMoverSetParent(GrabbedGameObject, originalParent.gameObject); - } - } + UnHighlightTarget(); + Reparent(originalParent.gameObject, false, true); RestoreOriginalAppearance(); } @@ -406,8 +618,7 @@ private static void NewVersion(GameObject grabbedObject) /// /// Moves the grabbed object to in world space. /// - /// the position where the grabbed object - /// should be moved in world space + /// the world-space position the grabbed object should be moved to /// the factor of the animation for moving the grabbed object /// This is only a movement, not a change to any hierarchy. private static void MoveTo(GameObject grabbedObject, Vector3 targetPosition, float factor = 1) @@ -416,22 +627,6 @@ private static void MoveTo(GameObject grabbedObject, Vector3 targetPosition, flo new MoveNetAction(grabbedObject.name, targetPosition, factor).Execute(); } - /// - /// Runs and propagates it to all clients. - /// - /// The will be an immediate child of in the - /// game-object hierarchy afterwards. - /// - /// the child to be put on - /// new parent of - /// original parent of - /// original local scale of - private static void PutOnAndFit(GameObject child, GameObject newParent, GameObject originalParent, Vector3 originalLocalScale) - { - GameNodeMover.PutOnAndFit(child.transform, newParent, originalParent, originalLocalScale); - new PutOnAndFitNetAction(child.name, newParent.name, originalParent.name, originalLocalScale).Execute(); - } - /// /// Runs and propagates it to all clients. /// @@ -475,147 +670,15 @@ private static void GameNodeMoverSetParent(GameObject child, GameObject parent) /// /// Resets the marking of the target node and moves - /// back to its and restores - /// its . + /// back to its . /// /// No changes are made to the game-node hierarchy or graph-node hierarchy. /// private void RestoreOriginalAppearance() { - UnmarkAsTarget(); + UnHighlightTarget(); MoveToOrigin(); - GrabbedGameObject.NodeOperator().ScaleTo(originalLocalScale); - new ScaleNodeNetAction(GrabbedGameObject.name, originalLocalScale).Execute(); } } - - /// - /// The currently grabbed object if any. - /// - private GrabbedObject grabbedObject; - - /// - /// The distance from the the position of when it was grabbed to - /// the origin of the user's pointing device (e.g., main camera on a desktop, controller - /// in VR) in world space. This distance will be maintained while the user has grabbed - /// an object. - /// - private float distanceToUser; - - /// - /// Reacts to the user interactions. An object can be grabbed and moved - /// around. If it is put onto another node, it will be re-parented onto this - /// node. If we are operating in a , re-parenting - /// may be a mapping of an implementation node onto an architecture node - /// or a hierarchical re-parenting. If we are operating in a different kind - /// of city, re-parenting is always hierarchically interpreted. A hierarchical - /// re-parenting means that the moved node becomes a child of the target node - /// both in the game-node hierarchy as well as in the underlying graph. - /// . - /// - /// true if completed - public override bool Update() - { - if (UserIsGrabbing()) // start to grab the object or continue to move the grabbed object - { - if (!grabbedObject.IsGrabbed) - { - // User is starting dragging the currently hovered object. - InteractableObject hoveredObject = InteractableObject.HoveredObjectWithWorldFlag; - // An object to be grabbed must be representing a node that is not the root. - if (hoveredObject && hoveredObject.gameObject.TryGetNode(out Node node) && !node.IsRoot()) - { - grabbedObject.Grab(hoveredObject.gameObject); - AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.PickupSound, hoveredObject.gameObject); - // Remember the current distance from the pointing device to the grabbed object. - distanceToUser = Vector3.Distance(Raycasting.UserPointsTo().origin, grabbedObject.Position); - CurrentState = IReversibleAction.Progress.InProgress; - } - } - else // continue moving the grabbed object - { - // The grabbed object will be moved on the surface of a sphere with - // radius distanceToUser in the direction the user is pointing to. - Ray ray = Raycasting.UserPointsTo(); - grabbedObject.MoveTo(ray.origin + distanceToUser * ray.direction); - } - - // The grabbed node is not yet at its final destination. The user is still moving - // it. We will run a what-if reflexion analysis to give immediate feedback on the - // consequences if the user were putting the grabbed node onto the node the user - // is currently aiming at. - UpdateHierarchy(); - } - else if (grabbedObject.IsGrabbed) // dragging has ended - { - // Finalize the action with the grabbed object. - if (grabbedObject.GrabbedGameObject != null) - { - AudioManagerImpl.EnqueueSoundEffect(IAudioManager.SoundEffect.DropSound, grabbedObject.GrabbedGameObject); - } - grabbedObject.UnGrab(); - // Action is finished. - CurrentState = IReversibleAction.Progress.Completed; - return true; - } - return false; - } - - /// - /// Returns true if the user is currently grabbing. - /// - /// true if user is grabbing - private static bool UserIsGrabbing() - { - // Index of the left mouse button. - const int leftMouseButton = 0; - // FIXME: We need a VR interaction, too. - return Input.GetMouseButton(leftMouseButton); - } - - /// - /// If no node is grabbed, nothing happens. Otherwise: - /// (1) If the user is currently pointing on a node, the grabbed object - /// will be re-parented onto this node (. - /// - /// (2) If the user currently not pointing to any node, the grabbed object - /// will be un-parented (. - /// - private void UpdateHierarchy() - { - if (grabbedObject.IsGrabbed) - { - if (Raycasting.RaycastLowestNode(out RaycastHit? raycastHit, out Node _, grabbedObject.Node)) - { - // Note: the root node can never be grabbed. See above. - // We need to undo the reparenting of the grabbed node if it is - // currently reparented onto another node. - grabbedObject.UnReparent(); - if (raycastHit.HasValue) - { - // The user is currently aiming at a node. The grabbed node is reparented onto this aimed node. - grabbedObject.Reparent(raycastHit.Value.transform.gameObject); - } - } - } - } - - /// - /// . - /// - public override void Undo() - { - base.Undo(); - grabbedObject.Undo(); - } - - /// - /// . - /// - public override void Redo() - { - base.Redo(); - grabbedObject.Redo(); - } } } diff --git a/Assets/SEE/Controls/Actions/NodeManipulationAction.cs b/Assets/SEE/Controls/Actions/NodeManipulationAction.cs index e0754dc2e3..bca279c947 100644 --- a/Assets/SEE/Controls/Actions/NodeManipulationAction.cs +++ b/Assets/SEE/Controls/Actions/NodeManipulationAction.cs @@ -1,8 +1,10 @@ using RTG; using SEE.Audio; using SEE.Game; +using SEE.Game.City; using SEE.Game.Operator; using SEE.GO; +using SEE.UI.Notification; using SEE.Utils; using SEE.Utils.History; using System.Collections.Generic; @@ -193,6 +195,17 @@ public override bool Update() /// game node to start the manipulation with protected void StartAction(GameObject gameNode) { + if (!gameNode.TryGetNodeRef(out NodeRef nodeRef)) + { + return; + } + VisualNodeAttributes gameNodeAttributes = gameNode.ContainingCity().NodeTypes[nodeRef.Value.Type]; + if (!gameNodeAttributes.AllowManualNodeManipulation) + { + ShowNotification.Info("Manipulation Forbidden", "The node cannot be manipulated!", 5, false); + return; + } + GameNodeSelected = gameNode; GameNodeMemento = CreateMemento(GameNodeSelected); UsedGizmo.Enable(GameNodeSelected); @@ -220,6 +233,18 @@ protected virtual void FinalizeAction() /// true if has had a change protected abstract bool HasChanges(); + /// + /// Used to execute the from the context menu. + /// It ensures that the method performs the execution via context menu for + /// the selected game object . + /// + /// The object to be modify. + public void ContextMenuExecution(GameObject obj) + { + ExecuteViaContextMenu = true; + StartAction(obj); + } + #endregion Update #region Memento diff --git a/Assets/SEE/Controls/Actions/ResizeNodeAction.cs b/Assets/SEE/Controls/Actions/ResizeNodeAction.cs new file mode 100644 index 0000000000..c0c80f3a9e --- /dev/null +++ b/Assets/SEE/Controls/Actions/ResizeNodeAction.cs @@ -0,0 +1,824 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using SEE.DataModel.DG; +using SEE.Game.City; +using SEE.GO; +using SEE.Net.Actions; +using SEE.Utils; +using SEE.Utils.History; + +namespace SEE.Controls.Actions +{ + /// + /// Action to resize a node. + /// + internal class ResizeNodeAction : AbstractPlayerAction + { + /// + /// The memento holding the information for and . + /// + private Memento memento; + + /// + /// Reference to the resize gizmo that is attached to the game object during resize. + /// + private ResizeGizmo gizmo; + + /// + /// Whether the action is finished and can be completed. + /// + private bool finished = false; + + #region ReversibleAction + + /// + /// Returns a new instance of . + /// + /// new instance + internal static IReversibleAction CreateReversibleAction() => new ResizeNodeAction(); + + /// + /// Returns a new instance of . + /// + /// new instance + public override IReversibleAction NewInstance() => new ResizeNodeAction(); + + /// + /// Returns the of this action. + /// + /// + public override ActionStateType GetActionStateType() + { + return ActionStateTypes.ResizeNode; + } + + /// + /// Returns all IDs of gameObjects manipulated by this action. + /// + /// all IDs of gameObjects manipulated by this action + public override HashSet GetChangedObjects() + { + return memento.GameObject == null || CurrentState == IReversibleAction.Progress.NoEffect + ? new HashSet() + : new HashSet() { memento.GameObject.name }; + } + + /// . + /// + /// true if completed + public override bool Update() + { + if (finished) + { + CurrentState = IReversibleAction.Progress.Completed; + } + return CurrentState == IReversibleAction.Progress.Completed; + } + + /// + /// Starts this . + /// + public override void Start() + { + base.Start(); + + InteractableObject.MultiSelectionAllowed = false; + InteractableObject.LocalAnySelectIn += OnSelectionChanged; + InteractableObject.LocalAnySelectOut += OnSelectionChanged; + } + + /// + /// Stops this without completing it. + /// + public override void Stop() + { + base.Stop(); + + InteractableObject.LocalAnySelectIn -= OnSelectionChanged; + InteractableObject.LocalAnySelectOut -= OnSelectionChanged; + InteractableObject.MultiSelectionAllowed = true; + + if (gizmo != null) + { + gizmo.OnSizeChanged -= OnResizeStep; + Destroyer.Destroy(gizmo); + } + + if (CurrentState == IReversibleAction.Progress.NoEffect) + { + memento = new Memento(); + } + + } + + /// + /// Undoes this ResizeNodeAction. + /// + public override void Undo() + { + base.Undo(); + + if (memento.GameObject == null) + { + return; + } + + memento.GameObject.NodeOperator().ResizeTo(memento.OriginalLocalScale, memento.OriginalPosition); + new ResizeNodeNetAction(memento.GameObject.name, memento.OriginalLocalScale, memento.OriginalPosition).Execute(); + } + + /// + /// Redoes this ResizeNodeAction. + /// + public override void Redo() + { + base.Redo(); + + if (memento.GameObject == null) + { + return; + } + + memento.GameObject.NodeOperator().ResizeTo(memento.NewLocalScale, memento.NewPosition); + new ResizeNodeNetAction(memento.GameObject.name, memento.NewLocalScale, memento.NewPosition).Execute(); + } + + #endregion ReversibleAction + + /// + /// Used to execute the from the context menu. + /// + /// The object to be resize + /// + /// This method does not check if the object's type has + /// flag set. + /// + public void ContextMenuExecution(GameObject go) + { + ExecuteViaContextMenu = true; + InteractableObject.UnselectAll(true); + InteractableObject interactable = go.GetComponent(); + interactable.SetSelect(true, true); + + InteractableObject.MultiSelectionAllowed = false; + InteractableObject.LocalAnySelectIn += OnSelectionChanged; + InteractableObject.LocalAnySelectOut += OnSelectionChanged; + } + + /// + /// Event handler that is called every time the node selection in changes. + /// + private void OnSelectionChanged(InteractableObject interactableObject) + { + // Interactable object is deselected when a handle is clicked, so we cannot stop here… + if (!interactableObject.IsSelected || InteractableObject.SelectedObjects.Count != 1) + { + return; + } + + // New selection + if (memento.GameObject != null && interactableObject.gameObject != memento.GameObject) + { + Stop(); + + if (CurrentState == IReversibleAction.Progress.InProgress) + { + finished = true; + } + return; + } + + // Incompatible type + GameObject selectedGameObject = interactableObject.gameObject; + if (!selectedGameObject.TryGetNodeRef(out NodeRef selectedNodeRef) + || !selectedGameObject.ContainingCity().NodeTypes[selectedNodeRef.Value.Type].AllowManualNodeManipulation) + { + return; + } + + // Start resizing + memento = new Memento(selectedGameObject); + gizmo = memento.GameObject.AddOrGetComponent(); + gizmo.OnSizeChanged += OnResizeStep; + } + + /// + /// Event handler that is called by each time a resize step is finished. + /// + /// One resize step is finished each time a handle is released. This, however, does not finish the + /// . + /// + /// + /// The new local scale after the resize step + /// The new world-space position after the resize step + private void OnResizeStep(Vector3 newLocalScale, Vector3 newPosition) + { + CurrentState = IReversibleAction.Progress.InProgress; + + memento.NewLocalScale = newLocalScale; + memento.NewPosition = newPosition; + + // Apply new position and scale to update edges and propagate changes to other players + memento.GameObject.NodeOperator().ResizeTo(newLocalScale, newPosition, 0, reparentChildren: false); + new ResizeNodeNetAction(memento.GameObject.name, newLocalScale, newPosition).Execute(); + } + + /// + /// The metadata of a resize action that affects the scale and position of a node. + /// + private struct Memento + { + /// + /// The GameObject of the game object. + /// + public readonly GameObject GameObject; + + /// + /// The original world-space position of the game object. + /// + public readonly Vector3 OriginalPosition; + + /// + /// The original scale of the game object. + /// + public readonly Vector3 OriginalLocalScale; + + /// + /// The new world-space position of the game object. + /// + public Vector3 NewPosition; + + /// + /// The new scale of the game object. + /// + public Vector3 NewLocalScale; + + /// + /// Constructs a . + /// + public Memento(GameObject go) + { + GameObject = go; + OriginalPosition = go.transform.position; + OriginalLocalScale = go.transform.localScale; + NewPosition = OriginalPosition; + NewLocalScale = OriginalLocalScale; + } + } + + /// + /// Added as a component to a game object, this will add handles for manual resize. + /// + /// The event is emitted each time the user finishes a resize + /// step. To conclude the resize process, the component should be destroyed. + /// + /// + private class ResizeGizmo : MonoBehaviour + { + /// + /// The data of the resize step that is in action. + /// + private ResizeStepData currentResizeStep; + + /// + /// The node reference. + /// + private NodeRef nodeRef; + + /// + /// Stores the directional vectors that belong to the individual handles. + /// + private Dictionary handles; + + /// + /// Used to remember if a click was detected in an earlier frame. + /// + private bool clicked = false; + + #region Configurations + + /// + /// The minimal size of a node in world space. + /// + private const float minSize = 0.04f; + + /// + /// The minimal world-space distance between nodes while resizing. + /// + private const float padding = 0.004f; + + /// + /// A small offset is used as a difference between the detection and the set value + /// to prevent instant re-detection. + /// + private const float detectionOffset = 0.0001f; + + /// + /// The size of the handles. + /// + private static readonly Vector3 handleScale = new(0.02f, 0.02f, 0.02f); + + /// + /// The color of the handles. + /// + private static Color handleColor = Color.cyan; + + #endregion Configurations + + #region Change Event + + /// + /// The event is emitted each time a resize step has finished. + /// + public event Action OnSizeChanged; + + #endregion Change Event + + /// + /// Initializes the . + /// + /// + /// Thrown when the object script is attached to is not a node, i.e., has no NodeRef + /// component. + /// + private void Start() + { + if (!gameObject.TryGetNodeRef(out NodeRef nodeRef)) + { + throw new InvalidOperationException("Can only be attached to GameObjects with NodeRef!"); + } + + this.nodeRef = nodeRef; + InitHandles(); + } + + /// + /// Destroys the handles. + /// + private void OnDestroy() + { + if (handles == null) + { + return; + } + foreach (GameObject handle in handles.Keys) + { + Destroyer.Destroy(handle); + } + } + + /// + /// Manages the resize steps. + /// + /// A resize step starts when a handle is clicked and it ends when the handle is released. + /// + /// Calls when a new step is detected. + /// + /// During the resize step progress, each frame is called. + /// + /// + private void Update() + { + bool newClick = false; + if (Input.GetMouseButton(0)) + { + newClick = !clicked; + clicked = true; + } + else if (clicked) + { + clicked = false; + currentResizeStep = new(); + OnSizeChanged?.Invoke(transform.localScale, transform.position); + } + + if (newClick) + { + StartResizing(); + } + + if (currentResizeStep.IsSet) + { + UpdateSize(); + } + } + + /// + /// Initializes the resize handles and stores them in + /// together with the direction vector. + /// + private void InitHandles() + { + handles = new Dictionary(); + + Vector3[] directions = new[] { Vector3.right, Vector3.left, Vector3.forward, Vector3.back, + Vector3.right + Vector3.forward, Vector3.right + Vector3.back, + Vector3.left + Vector3.forward, Vector3.left + Vector3.back }; + Vector3 position = transform.position; + Vector3 size = gameObject.WorldSpaceSize(); + foreach (Vector3 direction in directions) + { + handles[CreateHandle(direction, position, size)] = direction; + } + } + + /// + /// Creates a resize handle game object at the appropriate position. + /// + /// The direction for which the handle is created. + /// The cached parent world-space position. + /// The cached parent world-space scale. + private GameObject CreateHandle(Vector3 direction, Vector3 parentWorldPosition, Vector3 parentWorldScale) + { + GameObject handle = GameObject.CreatePrimitive(PrimitiveType.Cube); + handle.GetComponent().material.color = handleColor; + handle.transform.localScale = handleScale; + handle.transform.localPosition = parentWorldPosition + 0.5f * Vector3.Scale(parentWorldScale, direction); + handle.name = $"handle__{direction.x}_{direction.y}_{direction.z}"; + handle.transform.SetParent(transform); + return handle; + } + + /// + /// Starts a resize step if a handle is selected. + /// + /// If the user points to a handle, the attribute is set + /// to the respective direction vector and the current transform values. + /// + /// + void StartResizing() + { + if (!Raycasting.RaycastAnything(out RaycastHit hit)) + { + return; + } + Vector3? resizeDirection = handles.TryGetValue(hit.collider.gameObject, out Vector3 value) ? value : null; + if (resizeDirection == null) + { + return; + } + + currentResizeStep = new(hit.point, resizeDirection.Value, transform); + } + + /// + /// Does the actual resizing (scaling and positioning). + /// + void UpdateSize() + { + Raycasting.RaycastLowestNode(out RaycastHit? targetObjectHit, out Node hitNode, nodeRef); + if (!targetObjectHit.HasValue) + { + return; + } + + // Collect siblings + Transform parent = transform.parent; + // We use an initial size of the list so that the memory does not need to get + // reallocated each time an item is added. + List siblings = new(parent.childCount); + foreach (Transform sibling in parent) + { + if (sibling != transform && sibling.gameObject.IsNodeAndActiveSelf()) + { + siblings.Add(sibling); + } + } + + // Collect children + List children = new(transform.childCount); + foreach (Transform child in transform) + { + if (child.gameObject.IsNodeAndActiveSelf()) + { + children.Add(child); + } + } + + // Calculate new scale and position + Vector3 hitPoint = targetObjectHit.Value.point; + Vector3 cursorMovement = Vector3.Scale(currentResizeStep.InitialHitPoint - hitPoint, currentResizeStep.Direction); + Vector3 newLocalSize = currentResizeStep.InitialLocalSize - Vector3.Scale(currentResizeStep.LocalScaleFactor, cursorMovement); + Vector3 newLocalPosition = currentResizeStep.InitialLocalPosition + - 0.5f * Vector3.Scale(currentResizeStep.LocalScaleFactor, Vector3.Scale(cursorMovement, currentResizeStep.Direction)); + + // Contain in parent + Bounds2D bounds = new( + newLocalPosition.x - newLocalSize.x / 2, + newLocalPosition.x + newLocalSize.x / 2, + newLocalPosition.z - newLocalSize.z / 2, + newLocalPosition.z + newLocalSize.z / 2 + ); + // Parent scale in its own context is always 1 + Bounds2D otherBounds = new( + -0.5f + currentResizeStep.LocalPadding.x, + 0.5f - currentResizeStep.LocalPadding.x, + -0.5f + currentResizeStep.LocalPadding.z, + 0.5f - currentResizeStep.LocalPadding.z + ); + if (currentResizeStep.Left && bounds.Left < otherBounds.Left) + { + bounds.Left = otherBounds.Left; + } + if (currentResizeStep.Right && bounds.Right > otherBounds.Right) + { + bounds.Right = otherBounds.Right; + } + if (currentResizeStep.Back && bounds.Back < otherBounds.Back) + { + bounds.Back = otherBounds.Back; + } + if (currentResizeStep.Forward && bounds.Front > otherBounds.Front) + { + bounds.Front = otherBounds.Front; + } + + // Correct sibling overlap + foreach (Transform sibling in siblings) + { + Vector3 siblingSize = sibling.gameObject.LocalSize(); + Vector3 siblingPos = sibling.localPosition; + otherBounds.Left = siblingPos.x - siblingSize.x / 2 - currentResizeStep.LocalPadding.x + detectionOffset; + otherBounds.Right = siblingPos.x + siblingSize.x / 2 + currentResizeStep.LocalPadding.x - detectionOffset; + otherBounds.Back = siblingPos.z - siblingSize.z / 2 - currentResizeStep.LocalPadding.z + detectionOffset; + otherBounds.Front = siblingPos.z + siblingSize.z / 2 + currentResizeStep.LocalPadding.z - detectionOffset; + + if (bounds.Back > otherBounds.Front || bounds.Front < otherBounds.Back + || bounds.Left > otherBounds.Right || bounds.Right < otherBounds.Left) + { + // No overlap detected + continue; + } + + // Calculate overlap + float[] overlap = { float.MaxValue, float.MaxValue }; + if (currentResizeStep.Right) + { + overlap[0] = bounds.Right - otherBounds.Left; + } + if (currentResizeStep.Left) + { + overlap[0] = otherBounds.Right - bounds.Left; + } + if (currentResizeStep.Forward) + { + overlap[1] = bounds.Front - otherBounds.Back; + } + if (currentResizeStep.Back) + { + overlap[1] = otherBounds.Front - bounds.Back; + } + + // Pick correction direction + if (overlap[0] < overlap[1] && newLocalSize.x - overlap[0] > currentResizeStep.MinLocalSize.x) + { + if (currentResizeStep.Right) + { + bounds.Right = otherBounds.Left - detectionOffset; + } + else + { + bounds.Left = otherBounds.Right + detectionOffset; + } + } + else if (newLocalSize.z - overlap[1] > currentResizeStep.MinLocalSize.z) + { + if (currentResizeStep.Forward) + { + bounds.Front = otherBounds.Back - detectionOffset; + } + else + { + bounds.Back = otherBounds.Front + detectionOffset; + } + } + } + + // Contain all children + foreach (Transform child in children) + { + // Child position and scale on common parent + Vector3 childPos = Vector3.Scale(child.localPosition, transform.localScale) + transform.localPosition; + Vector3 childSize = Vector3.Scale(child.gameObject.LocalSize(), transform.localScale); + otherBounds.Left = childPos.x - childSize.x / 2 - currentResizeStep.LocalPadding.x + detectionOffset; + otherBounds.Right = childPos.x + childSize.x / 2 + currentResizeStep.LocalPadding.x - detectionOffset; + otherBounds.Back = childPos.z - childSize.z / 2 - currentResizeStep.LocalPadding.z + detectionOffset; + otherBounds.Front = childPos.z + childSize.z / 2 + currentResizeStep.LocalPadding.z - detectionOffset; + + if (currentResizeStep.Right && bounds.Right < otherBounds.Right) + { + bounds.Right = otherBounds.Right + detectionOffset; + } + + if (currentResizeStep.Left && bounds.Left > otherBounds.Left) + { + bounds.Left = otherBounds.Left - detectionOffset; + } + + + if (currentResizeStep.Forward && bounds.Front < otherBounds.Front) + { + bounds.Front = otherBounds.Front + detectionOffset; + } + + if (currentResizeStep.Back && bounds.Back > otherBounds.Back) + { + bounds.Back = otherBounds.Back - detectionOffset; + } + } + + newLocalSize.x = bounds.Right - bounds.Left; + newLocalSize.z = bounds.Front - bounds.Back; + newLocalPosition.x = bounds.Left + newLocalSize.x / 2; + newLocalPosition.z = bounds.Back + newLocalSize.z / 2; + + // Ensure minimal size + if (newLocalSize.x < currentResizeStep.MinLocalSize.x || newLocalSize.z < currentResizeStep.MinLocalSize.z) + { + return; + } + + // Prevent child nodes from getting scaled + Transform tempParent = transform.parent; + foreach (Transform childNode in children) + { + childNode.SetParent(tempParent); + } + + // Apply new scale and position + transform.localScale = Vector3.Scale(newLocalSize, currentResizeStep.ScaleSizeFactor); + transform.localPosition = newLocalPosition; + + // Reparent children + foreach (Transform child in children) + { + child.SetParent(transform); + } + + // Restore handle scale + foreach (GameObject handle in handles.Keys) + { + handle.transform.SetParent(null); + handle.transform.localScale = handleScale; + handle.transform.SetParent(transform); + } + } + + /// + /// Data structure for the individual resize steps. + /// + private readonly struct ResizeStepData + { + /// + /// Whether the struct has been explicitly initialized with values. + /// + public readonly bool IsSet; + + /// + /// The initial raycast hit from which the resize step is started. + /// + public readonly Vector3 InitialHitPoint; + + /// + /// The resize direction. + /// + public readonly Vector3 Direction; + + /// + /// The position right before the resize step is started. + /// + public readonly Vector3 InitialLocalPosition; + + /// + /// The local size right before the resize step is started. + /// + public readonly Vector3 InitialLocalSize; + + /// + /// The factor to convert from local size to local scale. + /// + public readonly Vector3 ScaleSizeFactor; + + /// + /// The factor to convert world-space to local coordinates in the parent's + /// coordinate system for the resize step. + /// + public readonly Vector3 LocalScaleFactor; + + /// + /// The scaled by . + /// + public readonly Vector3 MinLocalSize; + + /// + /// The scaled by . + /// This is effectively the local-space padding in parent, e.g., between + /// the resized object and its siblings. + /// + public readonly Vector3 LocalPadding; + + /// + /// Does point to the left? + /// + public readonly bool Left; + + /// + /// Does point to the right? + /// + public readonly bool Right; + + /// + /// Does point forward? + /// + public readonly bool Forward; + + /// + /// Does point backward? + /// + public readonly bool Back; + + /// + /// Initializes the struct. + /// + public ResizeStepData (Vector3 initialHitPoint, Vector3 direction, Transform transform) + { + InitialHitPoint = initialHitPoint; + Direction = direction; + InitialLocalPosition = transform.localPosition; + InitialLocalSize = transform.gameObject.LocalSize(); + Vector3 localScale = transform.localScale; + ScaleSizeFactor = new( + InitialLocalSize.x / localScale.x, + InitialLocalSize.y / localScale.y, + InitialLocalSize.z / localScale.z + ); + Vector3 lossyScale = transform.lossyScale; + LocalScaleFactor = new( + localScale.x / lossyScale.x, + localScale.y / lossyScale.y, + localScale.z / lossyScale.z + ); + IsSet = true; + MinLocalSize = minSize * LocalScaleFactor; + LocalPadding = padding * LocalScaleFactor; + Left = Direction.x < 0; + Right = Direction.x > 0; + Back = Direction.z < 0; + Forward = Direction.z > 0; + } + } + + /// + /// Data structure for 2-dimensional bounds. + /// + private struct Bounds2D + { + /// + /// The left side of the area. + /// + public float Left; + /// + /// The right side of the area. + /// + public float Right; + /// + /// The back side of the area. + /// + public float Back; + /// + /// The front side of the area. + /// + public float Front; + + /// + /// Initializes the struct. + /// + public Bounds2D (float left, float right, float back, float front) + { + Left = left; + Right = right; + Back = back; + Front = front; + } + + /// + /// Implicit conversion to string. + /// + public static implicit operator string(Bounds2D bounds) + { + return bounds.ToString(); + } + + /// + /// Returns a printable string with the struct's values. + /// + public override readonly string ToString() + { + return $"{nameof(Bounds2D)}(Left: {Left}, Right: {Right}, Bottom: {Back}, Top: {Front})"; + } + } + } + } +} diff --git a/Assets/SEE/Net/Actions/ZoomNetAction.cs.meta b/Assets/SEE/Controls/Actions/ResizeNodeAction.cs.meta similarity index 83% rename from Assets/SEE/Net/Actions/ZoomNetAction.cs.meta rename to Assets/SEE/Controls/Actions/ResizeNodeAction.cs.meta index 49eeeb07c9..9ae5a32229 100644 --- a/Assets/SEE/Net/Actions/ZoomNetAction.cs.meta +++ b/Assets/SEE/Controls/Actions/ResizeNodeAction.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c9abcec227a331f45a2bc0addc501745 +guid: 99781f53228c4b2339f6a8816e1a353a MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/SEE/Controls/Actions/ShowLabel.cs b/Assets/SEE/Controls/Actions/ShowLabel.cs index f4e86969d9..b25db52ccd 100644 --- a/Assets/SEE/Controls/Actions/ShowLabel.cs +++ b/Assets/SEE/Controls/Actions/ShowLabel.cs @@ -160,7 +160,7 @@ public void On() if (nodeOperator.Node != null) { LabelAttributes settings = GetLabelSettings(nodeOperator.Node, nodeOperator.City); - if (settings.Show && pointer.Value.On) + if (settings.Show && pointer.Value.On && nodeOperator.LabelIsNotEmpty()) { nodeOperator.FadeLabel(settings.LabelAlpha, pointer.Value.LastHit, settings.AnimationFactor); } diff --git a/Assets/SEE/Controls/Actions/ZoomAction.cs b/Assets/SEE/Controls/Actions/ZoomAction.cs index 71c53d39f3..eac43e0e1a 100644 --- a/Assets/SEE/Controls/Actions/ZoomAction.cs +++ b/Assets/SEE/Controls/Actions/ZoomAction.cs @@ -29,6 +29,10 @@ protected class ZoomCommand /// internal readonly Vector2 ZoomCenter; /// + /// Should the position be reset to original position? + /// + internal readonly bool ResetPosition; + /// /// The amount of time in seconds that it should take to reach . /// private readonly float duration; @@ -37,12 +41,13 @@ protected class ZoomCommand /// private readonly float startTime; - internal ZoomCommand(Vector2 zoomCenter, float targetZoomSteps, float duration) + internal ZoomCommand(Vector2 zoomCenter, float targetZoomSteps, float duration, bool resetPosition = false) { TargetZoomSteps = targetZoomSteps; ZoomCenter = zoomCenter; this.duration = duration; startTime = Time.realtimeSinceStartup; + ResetPosition = resetPosition; } /// @@ -82,16 +87,20 @@ protected struct ZoomState /// /// The maximal number of zooming steps. /// - internal const uint ZoomMaxSteps = 32; + internal const uint ZoomMaxSteps = 10; /// /// Handles the speed in which we zoom into the city. /// internal const float ZoomFactor = 0.5f; /// - /// Original scale of city for reset. + /// Original local scale of city for reset. /// - internal Vector3 OriginalScale; + internal Vector3 OriginalLocalScale; + /// + /// Original world-space position of city for reset. + /// + internal Vector3 OriginalPosition; /// /// The list of active zoom commands, that is, those that are still to be executed. @@ -109,6 +118,11 @@ protected struct ZoomState /// /// Pushes a zoom command for execution. Zoom commands are automatically removed /// once they are finished. + /// + /// The position will automatically be reset if + + /// equals 0, i.e., the zoom factor reaches 1. + /// Otherwise, is used for calculating the new position. + /// /// /// The position to be zoomed towards. /// The desired amount of zoom steps. @@ -119,7 +133,7 @@ internal void PushZoomCommand(Vector2 zoomCenter, float zoomSteps, float duratio if (zoomSteps != 0.0f) { float newZoomStepsInProgress = CurrentTargetZoomSteps + zoomSteps; - ZoomCommands.Add(new ZoomCommand(zoomCenter, zoomSteps, duration)); + ZoomCommands.Add(new ZoomCommand(zoomCenter, zoomSteps, duration, Mathf.Approximately(CurrentTargetZoomSteps + zoomSteps, 0))); CurrentTargetZoomSteps = newZoomStepsInProgress; } } @@ -128,20 +142,20 @@ internal void PushZoomCommand(Vector2 zoomCenter, float zoomSteps, float duratio /// /// The zoom states for every root transform of a city. Once the first zoom is initiated, /// the zoom state will be inserted here. - /// + /// /// The key of this mapping is the root game node (tagged by ) /// of the game-object hierarchy. It is the game object that will be zoomed; /// all its descendants are scaled along with it. - /// + /// /// Because we may have multiple code cities in the scene, there is not only one such /// root node. /// - private readonly Dictionary rootTransformToZoomStates = new Dictionary(); + private readonly Dictionary rootTransformToZoomStates = new(); /// /// The node operator for every root transform of a city. /// - private readonly Dictionary rootTransformToOperator = new Dictionary(); + private readonly Dictionary rootTransformToOperator = new(); /// /// Factor to apply to the animation. @@ -173,12 +187,14 @@ private void FixedUpdate() // If there is any zoom command, execute it. float zoomSteps = zoomState.CurrentTargetZoomSteps; int positionCount = 0; - Vector2 positionSum = Vector3.zero; + Vector2 positionSum = Vector2.zero; + bool resetPosition = false; for (int i = 0; i < zoomState.ZoomCommands.Count; i++) { positionCount++; positionSum += zoomState.ZoomCommands[i].ZoomCenter; + resetPosition = zoomState.ZoomCommands[i].ResetPosition; if (zoomState.ZoomCommands[i].IsFinished()) { zoomState.ZoomCommands.RemoveAt(i--); @@ -188,25 +204,20 @@ private void FixedUpdate() zoomSteps -= zoomState.ZoomCommands[i].TargetZoomSteps - zoomState.ZoomCommands[i].CurrentDeltaScale(); } } - Vector3 averagePosition = new Vector3(positionSum.x / positionCount, rootTransform.position.y, positionSum.y / positionCount); zoomState.CurrentZoomFactor = ConvertZoomStepsToZoomFactor(zoomSteps); - Vector3 cityCenterToHitPoint = averagePosition - rootTransform.position; - Vector3 cityCenterToHitPointUnscaled = cityCenterToHitPoint.DividePairwise(rootTransform.localScale); - - nodeOperator.ScaleTo(zoomState.CurrentZoomFactor * zoomState.OriginalScale, AnimationFactor); - nodeOperator.MoveTo(rootTransform.position + cityCenterToHitPoint - Vector3.Scale(cityCenterToHitPointUnscaled, nodeOperator.TargetScale), AnimationFactor); - - new ZoomNetAction(rootTransform.name, nodeOperator.TargetPosition, nodeOperator.TargetScale).Execute(); - } - else - { - float lastZoomFactor = zoomState.CurrentZoomFactor; - zoomState.CurrentZoomFactor = ConvertZoomStepsToZoomFactor(zoomState.CurrentTargetZoomSteps); - if (!Mathf.Approximately(lastZoomFactor, zoomState.CurrentZoomFactor)) + Vector3 targetScale = zoomState.CurrentZoomFactor * zoomState.OriginalLocalScale; + Vector3 targetPosition = zoomState.OriginalPosition; + if (!resetPosition) { - nodeOperator.ScaleTo(zoomState.CurrentZoomFactor * zoomState.OriginalScale, AnimationFactor); + Vector3 averagePosition = new(positionSum.x / positionCount, rootTransform.position.y, positionSum.y / positionCount); + Vector3 cityCenterToHitPoint = averagePosition - rootTransform.position; + Vector3 cityCenterToHitPointUnscaled = cityCenterToHitPoint.DividePairwise(rootTransform.localScale); + targetPosition = rootTransform.position + cityCenterToHitPoint - Vector3.Scale(cityCenterToHitPointUnscaled, nodeOperator.TargetScale); } + + nodeOperator.ResizeTo(targetScale, targetPosition, AnimationFactor, true, false); + new ResizeNodeNetAction(rootTransform.name, targetScale, targetPosition, true, false).Execute(); } } } @@ -224,7 +235,8 @@ protected ZoomState GetZoomStateCopy(Transform transform) { result = new ZoomState { - OriginalScale = transform.localScale, + OriginalLocalScale = transform.localScale, + OriginalPosition = transform.position, ZoomCommands = new List((int)ZoomState.ZoomMaxSteps), CurrentTargetZoomSteps = 0, CurrentZoomFactor = 1.0f diff --git a/Assets/SEE/Controls/Actions/ZoomActionDesktop.cs b/Assets/SEE/Controls/Actions/ZoomActionDesktop.cs index d087d05160..a5e229d26f 100644 --- a/Assets/SEE/Controls/Actions/ZoomActionDesktop.cs +++ b/Assets/SEE/Controls/Actions/ZoomActionDesktop.cs @@ -98,7 +98,6 @@ private void Update() // as requested per mouse wheel. if (zoomTowards) { - zoomSteps = Mathf.Clamp(zoomSteps, -(int)zoomState.CurrentTargetZoomSteps, (int)ZoomState.ZoomMaxSteps - (int)zoomState.CurrentTargetZoomSteps); zoomState.PushZoomCommand(hitPointOnPlane.XZ(), zoomSteps, ZoomState.DefaultZoomDuration); } diff --git a/Assets/SEE/Controls/Interactables/InteractableObject.cs b/Assets/SEE/Controls/Interactables/InteractableObject.cs index f2239ae8aa..85d008dd2c 100644 --- a/Assets/SEE/Controls/Interactables/InteractableObject.cs +++ b/Assets/SEE/Controls/Interactables/InteractableObject.cs @@ -11,6 +11,7 @@ #endif using SEE.Net.Actions; using SEE.Audio; +using SEE.Game.Operator; namespace SEE.Controls { @@ -77,6 +78,11 @@ public sealed class InteractableObject : MonoBehaviour /// public static readonly HashSet GrabbedObjects = new(); + /// + /// If multiple objects should be selectable at the same time. + /// + public static bool MultiSelectionAllowed = true; + /// /// The selected objects per graph. /// @@ -354,6 +360,11 @@ public void SetSelect(bool select, bool isInitiator) { Assert.IsTrue(IsSelected != select); + if (select && !MultiSelectionAllowed && SelectedObjects.Count > 0) + { + return; + } + IsSelected = select; if (select) @@ -371,7 +382,12 @@ public void SetSelect(bool select, bool isInitiator) graphToSelectedIOs[graph].Add(this); // Start blinking indefinitely. - gameObject.Operator().Blink(-1); + GraphElementOperator op = gameObject.Operator(); + op.Blink(-1); + if (op is EdgeOperator eop) + { + eop.AnimateDataFlow(true); + } // Invoke events SelectIn?.Invoke(this, isInitiator); @@ -393,7 +409,12 @@ public void SetSelect(bool select, bool isInitiator) graphToSelectedIOs[GraphElemRef.Elem.ItsGraph].Remove(this); // Stop blinking. - gameObject.Operator().Blink(0); + GraphElementOperator op = gameObject.Operator(); + op.Blink(0); + if (op is EdgeOperator eop) + { + eop.AnimateDataFlow(false); + } // Invoke events SelectOut?.Invoke(this, isInitiator); diff --git a/Assets/SEE/Game/City/VisualNodeAttributes.cs b/Assets/SEE/Game/City/VisualNodeAttributes.cs index cc5d7e7247..99b759664b 100644 --- a/Assets/SEE/Game/City/VisualNodeAttributes.cs +++ b/Assets/SEE/Game/City/VisualNodeAttributes.cs @@ -159,6 +159,11 @@ public string DepthMetric /// [Tooltip("Whether the source name will be added to a node.")] public bool ShowNames = false; + /// + /// Whether users may manipulate (e.g., resize) instances of this type of node. + /// + [Tooltip("Whether users may manipulate (e.g., resize) instances of this type of node.")] + public bool AllowManualNodeManipulation = false; /// /// Saves the settings in the configuration file. @@ -178,6 +183,7 @@ public override void Save(ConfigWriter writer, string label) AntennaSettings.Save(writer, antennaSettingsLabel); writer.Save(OutlineWidth, outlineWidthLabel); writer.Save(ShowNames, showNamesLabel); + writer.Save(AllowManualNodeManipulation, allowManualNodeManipulationLabel); writer.EndGroup(); } @@ -213,6 +219,7 @@ internal virtual void Restore(Dictionary values) AntennaSettings.Restore(values, antennaSettingsLabel); ConfigIO.Restore(values, outlineWidthLabel, ref OutlineWidth); ConfigIO.Restore(values, showNamesLabel, ref ShowNames); + ConfigIO.Restore(values, allowManualNodeManipulationLabel, ref AllowManualNodeManipulation); } /// @@ -255,5 +262,10 @@ internal virtual void Restore(Dictionary values) /// Label in the configuration file for . /// private const string showNamesLabel = "ShowNames"; + + /// + /// Label in the configuration file for . + /// + private const string allowManualNodeManipulationLabel = "AllowManualNodeManipulation"; } } diff --git a/Assets/SEE/Game/CityRendering/NodeRenderer.cs b/Assets/SEE/Game/CityRendering/NodeRenderer.cs index 3a0bbba05d..cc5b5132b3 100644 --- a/Assets/SEE/Game/CityRendering/NodeRenderer.cs +++ b/Assets/SEE/Game/CityRendering/NodeRenderer.cs @@ -511,7 +511,7 @@ private float GetMetricValue(Node node, string metricName) /// for inner node kinds and nodelayout. /// /// - protected void AddDecorations(GameObject gameNode) + public void AddDecorations(GameObject gameNode) { AddDecorations(new List { gameNode }); } diff --git a/Assets/SEE/Game/Drawable/ActionHelpers/Queries.cs b/Assets/SEE/Game/Drawable/ActionHelpers/Queries.cs index 824d723f8f..c1ddd8551b 100644 --- a/Assets/SEE/Game/Drawable/ActionHelpers/Queries.cs +++ b/Assets/SEE/Game/Drawable/ActionHelpers/Queries.cs @@ -13,12 +13,15 @@ public static class Queries /// true if the user uses the left mouse button. public static bool LeftMouseInteraction() { - return Input.GetMouseButton(0) || Input.GetMouseButtonDown(0); + return Input.GetMouseButton(0); } /// /// Registers the users left mouse down input. /// + /// + /// This is only true in the exact frame the mouse button is pressed down. + /// /// True if the user uses left mouse down. public static bool LeftMouseDown() { @@ -31,7 +34,7 @@ public static bool LeftMouseDown() /// true if the user uses the left mouse button. public static bool RightMouseInteraction() { - return Input.GetMouseButton(1) || Input.GetMouseButtonDown(1); + return Input.GetMouseButton(1); } /// diff --git a/Assets/SEE/Game/Operator/EdgeDirectionVisualizer.cs b/Assets/SEE/Game/Operator/EdgeDirectionVisualizer.cs new file mode 100644 index 0000000000..7fcf3695ea --- /dev/null +++ b/Assets/SEE/Game/Operator/EdgeDirectionVisualizer.cs @@ -0,0 +1,154 @@ +using System.Linq; +using MoreLinq; +using SEE.GO; +using SEE.Utils; +using UnityEngine; + +namespace SEE.Game.Operator +{ + /// + /// Provides the to the . + /// + public partial class EdgeOperator : GraphElementOperator<(Color start, Color end)> + { + /// + /// Implements a data flow visualization to indicate the direction of an edge. + /// + private class EdgeDirectionVisualizer : MonoBehaviour + { + /// + /// Maximal count of particles. + /// + private const int maxParticleCount = 12; + /// + /// Minimal distance between particles for the actual particle count. + /// + private const float minParticleDistance = 0.16f; + /// + /// Scale of the particle meshes. + /// + private static readonly Vector3 particleScale = new(0.012f, 0.012f, 0.012f); + /// + /// Color of the particle material. + /// + private static readonly Color particleColor = new(0.06f, 0.81f, 1.0f, 1.0f); + /// + /// Particle speed. + /// + private const float particleSpeed = 50f; + + /// + /// The spline the edge is based on. + /// + private SEESpline seeSpline; + /// + /// The coordinates of the edge's vertices. + /// + private Vector3[] vertices; + + /// + /// The actual particle count as calculated based on + /// and capped by . + /// + private int particleCount; + /// + /// The particle game objects. + /// + private GameObject[] particles; + /// + /// The current position of the particles. + /// + private float[] particlePositions; + + /// + /// Destroys the particles when the component is destroyed. + /// + private void OnDestroy() + { + foreach (GameObject particle in particles) + { + seeSpline.OnRendererChanged -= OnSplineChanged; + Destroyer.Destroy(particle); + } + } + + /// + /// Initializes the particles and fields. + /// + public void Start() + { + seeSpline = GetComponent(); + seeSpline.OnRendererChanged += OnSplineChanged; + vertices = seeSpline.GenerateVertices(); + + particleCount = (int)Mathf.Max(Mathf.Min(GetApproxEdgeLength() / minParticleDistance, maxParticleCount), 1); + + particles = new GameObject[particleCount]; + particlePositions = new float[particleCount]; + + float separation = vertices.Length / (float)particleCount; + for (int i = 0; i < particleCount; i++) + { + particles[i] = GameObject.CreatePrimitive(PrimitiveType.Sphere); + particles[i].GetComponent().material.color = particleColor; + particlePositions[i] = separation * i; + particles[i].transform.localScale = particleScale; + particles[i].transform.SetParent(transform); + particles[i].transform.localPosition = GetPositionOnEdge(particlePositions[i]); + } + } + + /// + /// Updates the position and color of the vertices. + /// + private void Update() + { + for (int i = 0; i < particleCount; i++) + { + particlePositions[i] += particleSpeed * Time.deltaTime; + if (particlePositions[i] >= vertices.Length) + { + particlePositions[i] = 0; + } + particles[i].transform.localPosition = GetPositionOnEdge(particlePositions[i]); + } + } + + /// + /// This callback is triggered whenever the spline has changed. + /// It will then re-calculate . + /// + private void OnSplineChanged() + { + vertices = seeSpline.GenerateVertices(); + } + + /// + /// Calculates the coordinate of the position on the edge by interpolating between two + /// neighboring vertices. + /// + /// The vertices of the edge are derived from the integer places of , + /// while the decimal places represent the progress between the two vertices. + /// + /// + /// The position on the edge between zero and + /// .Length - 1. + /// The coordinate of the position on the edge. + private Vector3 GetPositionOnEdge(float position) + { + if (position >= vertices.Length - 1) + { + return vertices[^1]; // last element + } + + return Vector3.Lerp(vertices[(int)position], vertices[(int)position + 1], position - (int)position); + } + + /// + /// Calculates the approximate length of the edge that is represented by . + /// + /// Approximate edge length. + private float GetApproxEdgeLength() => vertices.Pairwise(Vector3.Distance).Sum(); + } + } +} diff --git a/Assets/SEE/Controls/Actions/DrawAction.cs.meta b/Assets/SEE/Game/Operator/EdgeDirectionVisualizer.cs.meta similarity index 83% rename from Assets/SEE/Controls/Actions/DrawAction.cs.meta rename to Assets/SEE/Game/Operator/EdgeDirectionVisualizer.cs.meta index 78ba3c5c9a..12a81a5756 100644 --- a/Assets/SEE/Controls/Actions/DrawAction.cs.meta +++ b/Assets/SEE/Game/Operator/EdgeDirectionVisualizer.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 4a2f8a38aa579c94e8d7016b511a41a8 +guid: b7e1e625e7090fca797f6b19f170fd2b MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/SEE/Game/Operator/EdgeOperator.cs b/Assets/SEE/Game/Operator/EdgeOperator.cs index b281b81cee..1da8a02a23 100644 --- a/Assets/SEE/Game/Operator/EdgeOperator.cs +++ b/Assets/SEE/Game/Operator/EdgeOperator.cs @@ -143,6 +143,23 @@ public IOperationCallback ShowOrHide(bool show, EdgeAnimationKind animat }; } + /// + /// Enables or disables the data flow animation to indicate edge direction. + /// + /// Enable or disable animation. + public void AnimateDataFlow(bool enable = true) + { + if (enable) + { + gameObject.AddOrGetComponent(); + } + else + { + EdgeDirectionVisualizer edfv = gameObject.GetComponent(); + Destroyer.Destroy(edfv); + } + } + #endregion protected override IEnumerable AsEnumerable((Color start, Color end) color) diff --git a/Assets/SEE/Game/Operator/LabelOperator.cs b/Assets/SEE/Game/Operator/LabelOperator.cs index fbcc871baf..70483bfb46 100644 --- a/Assets/SEE/Game/Operator/LabelOperator.cs +++ b/Assets/SEE/Game/Operator/LabelOperator.cs @@ -1,6 +1,4 @@ -using System.Linq; using DG.Tweening; -using SEE.Controls.Actions; using SEE.GO; using SEE.Utils; using TMPro; @@ -48,6 +46,15 @@ public void UpdateLabelLayout(Vector3 labelBase) labelEndLinePosition.AnimateTo(DesiredLabelEndLinePosition, duration); } + /// + /// Returns true if the label is not empty. + /// + /// True if the label is not empty. + public bool LabelIsNotEmpty() + { + return !string.IsNullOrWhiteSpace(labelText?.text); + } + /// /// Creates and prepares the game object along with its components. /// If already exists, nothing will happen. diff --git a/Assets/SEE/Game/Operator/NodeOperator.cs b/Assets/SEE/Game/Operator/NodeOperator.cs index 710e8f6fbc..5360a34a63 100644 --- a/Assets/SEE/Game/Operator/NodeOperator.cs +++ b/Assets/SEE/Game/Operator/NodeOperator.cs @@ -191,6 +191,76 @@ public IOperationCallback MoveTo(Vector3 newPosition, float factor = 1, }, a => a); } + /// + /// Moves and scales the node at the same time. + /// + /// If is true> (default), children are not scaled and moved along. + /// For this purpose they are reparented to their grandparent during the animation and back to the original + /// parent after the animation has completed. + /// + /// + /// the desired new local scale + /// the desired new target position in world space + /// Factor to apply to the + /// that controls the animation duration. + /// If set to 0, will execute directly, that is, the value is set before control is returned to the caller. + /// + /// if true, the children are not moved and scaled along with their parent + /// if true, the connecting edges will be moved along with the node + /// An operation callback for the requested animation + public IOperationCallback ResizeTo + (Vector3 newLocalScale, + Vector3 newPosition, + float factor = 1, + bool updateEdges = true, + bool reparentChildren = true) + { + float duration = ToDuration(factor); + updateLayoutDuration = duration; + this.updateEdges = updateEdges; + + List children = null; + Transform originalParent = transform; + Transform tempParent = transform.parent; + if (reparentChildren) + { + children = new(transform.childCount); + foreach (Transform child in transform) + { + if (child.gameObject.IsNodeAndActiveSelf()) + { + children.Add(child); + } + } + reparent(tempParent); + } + + IOperationCallback animation = new AndCombinedOperationCallback + (new[] + { + positionX.AnimateTo(newPosition.x, duration), + positionY.AnimateTo(newPosition.y, duration), + positionZ.AnimateTo(newPosition.z, duration), + scale.AnimateTo(newLocalScale, duration) + }, + a => a); + animation.OnComplete(() => reparent(originalParent)); + animation.OnKill(() => reparent(originalParent)); + return animation; + + void reparent(Transform newParent) + { + if (!reparentChildren) + { + return; + } + foreach (Transform child in children) + { + child.SetParent(newParent); + } + } + } + /// /// Rotates the node to the given quaternion . /// diff --git a/Assets/SEE/Game/ReflexionMapper.cs b/Assets/SEE/Game/ReflexionMapper.cs index 37edccccaf..99b5378738 100644 --- a/Assets/SEE/Game/ReflexionMapper.cs +++ b/Assets/SEE/Game/ReflexionMapper.cs @@ -3,7 +3,6 @@ using SEE.GO; using SEE.Tools.ReflexionAnalysis; using System; -using System.Collections.Generic; using System.Linq; using UnityEngine; @@ -20,17 +19,28 @@ internal static class ReflexionMapper /// Maps onto distinguishing /// the following four cases regarding to which domains /// and belong to: - /// (1) implementation -> architecture: interpreted as an architecture mapping, - /// i.e., is mapped onto - /// in the architecture. - /// (2) implementation -> implementation: interpreted as a restructuring in the implementation - /// (3) architecture -> architecture: interpreted as a restructuring in the architecture - /// (4) architecture -> implementation: makes no sense; will be ignored - /// - /// In cases (2)-(3), becomes a child graph node of + /// + /// 1. + /// implementation -> architecture: interpreted as an architecture mapping, + /// i.e., is mapped onto + /// in the architecture. + /// + /// 2. + /// implementation -> implementation: interpreted as a restructuring in the implementation + /// + /// 3. + /// architecture -> architecture: interpreted as a restructuring in the architecture + /// + /// 4. + /// architecture -> implementation: makes no sense; will be ignored + /// + /// + /// In cases 2–3, becomes a child graph node of /// in the underlying graph. - /// In cases (1)-(3), becomes a child game object of + /// + /// In cases 1–3, becomes a child game object of /// . In all theses cases, the reflexion data is updated. + /// /// /// the node to be mapped /// the target which is mapped onto @@ -50,65 +60,67 @@ internal static void SetParent(GameObject mappingSource, GameObject mappingTarge } // The mapping is only possible if mapping target is actually a node. - if (mappingTarget.TryGetNode(out Node target)) + if (!mappingTarget.TryGetNode(out Node target)) { - // The source of the mapping - Node source = mappingSource.GetNode(); + return; + } - if (source.ItsGraph != target.ItsGraph) - { - throw new Exception("For a mapping, both nodes must be in the same graph."); - } + // The source of the mapping + Node source = mappingSource.GetNode(); - // implementation -> architecture - if (source.IsInImplementation() && target.IsInArchitecture()) - { - // If there is a previous mapping that already mapped the node - // on the current target, nothing needs to be done. - // If there is a previous mapping that mapped the node onto - // another target, the previous mapping must be reverted and the - // node must be mapped onto the new target. + if (source.ItsGraph != target.ItsGraph) + { + throw new Exception("For a mapping, both nodes must be in the same graph."); + } - reflexionCity.ReflexionGraph.AddToMapping(source, target, overrideMapping: true); - mappingSource.transform.SetParent(mappingTarget.transform); - } - // implementation -> implementation - else if (source.IsInImplementation() && target.IsInImplementation()) + // implementation -> architecture + if (source.IsInImplementation() && target.IsInArchitecture()) + { + // If there is a previous mapping that already mapped the node + // on the current target, nothing needs to be done. + // If there is a previous mapping that mapped the node onto + // another target, the previous mapping must be reverted and the + // node must be mapped onto the new target. + + reflexionCity.ReflexionGraph.AddToMapping(source, target, overrideMapping: true); + mappingSource.transform.SetParent(mappingTarget.transform); + } + // implementation -> implementation + else if (source.IsInImplementation() && target.IsInImplementation()) + { + if (reflexionCity.ReflexionGraph.IsExplicitlyMapped(source)) { - if (reflexionCity.ReflexionGraph.IsExplicitlyMapped(source)) - { - reflexionCity.ReflexionGraph.RemoveFromMapping(source); - } - // TODO (falko17): This branch and the next branch can be merged as soon - // as the general Unparent and AddChild methods are implemented. - // This changes the node hierarchy in the implementation only. - if (source.Parent != null) - { - // If `AddChildInImplementation` fails, the source will be left without a parent, hence the if. - // TODO: Implement a proper transaction model for the reflexion analysis. - reflexionCity.ReflexionGraph.UnparentInImplementation(source); - } - reflexionCity.ReflexionGraph.AddChildInImplementation(source, target); - mappingSource.transform.SetParent(mappingTarget.transform); + reflexionCity.ReflexionGraph.RemoveFromMapping(source); } - // architecture -> architecture - else if (source.IsInArchitecture() && target.IsInArchitecture()) + // TODO (#785): This branch and the next branch can be merged as soon + // as the general Unparent and AddChild methods are implemented. + // This changes the node hierarchy in the implementation only. + if (source.Parent != null) { - // TODO (falko17): This branch and the previous branch can be merged as soon - // as the general Unparent and AddChild methods are implemented. - // This changes the node hierarchy in the architecture only. - if (source.Parent != null) - { - reflexionCity.ReflexionGraph.UnparentInArchitecture(source); - } - reflexionCity.ReflexionGraph.AddChildInArchitecture(source, target); - mappingSource.transform.SetParent(mappingTarget.transform); + // If `AddChildInImplementation` fails, the source will be left without a parent, hence the if. + // TODO (#785): Implement a proper transaction model for the reflexion analysis. + reflexionCity.ReflexionGraph.UnparentInImplementation(source); } - // architecture -> implementation: forbidden - else + reflexionCity.ReflexionGraph.AddChildInImplementation(source, target); + mappingSource.transform.SetParent(mappingTarget.transform); + } + // architecture -> architecture + else if (source.IsInArchitecture() && target.IsInArchitecture()) + { + // TODO (#785): This branch and the previous branch can be merged as soon + // as the general Unparent and AddChild methods are implemented. + // This changes the node hierarchy in the architecture only. + if (source.Parent != null) { - // Nothing to be done. + reflexionCity.ReflexionGraph.UnparentInArchitecture(source); } + reflexionCity.ReflexionGraph.AddChildInArchitecture(source, target); + mappingSource.transform.SetParent(mappingTarget.transform); + } + // architecture -> implementation: forbidden + else + { + // Nothing to be done. } } diff --git a/Assets/SEE/Game/SceneManipulation/GameElementDeleter.cs b/Assets/SEE/Game/SceneManipulation/GameElementDeleter.cs index 5f7aa824c7..e351b893a1 100644 --- a/Assets/SEE/Game/SceneManipulation/GameElementDeleter.cs +++ b/Assets/SEE/Game/SceneManipulation/GameElementDeleter.cs @@ -123,9 +123,9 @@ private static (GraphElementsMemento, ISet) DeleteEdge(GameObject ga /// contained in this tree are the transitive descendants of . /// The edges in this tree are those whose source or target node /// is contained in the tree. - /// + /// /// Note: The result consists of both nodes and edges. - /// + /// /// Precondition: is a game node. /// /// the root of the tree to be deleted diff --git a/Assets/SEE/Game/SceneManipulation/GameNodeEditor.cs b/Assets/SEE/Game/SceneManipulation/GameNodeEditor.cs new file mode 100644 index 0000000000..d52d1b8d8a --- /dev/null +++ b/Assets/SEE/Game/SceneManipulation/GameNodeEditor.cs @@ -0,0 +1,97 @@ +using SEE.DataModel.DG; +using SEE.Game.City; +using SEE.Game.CityRendering; +using SEE.GO; +using SEE.Utils; +using TMPro; +using UnityEngine; + +namespace SEE.Game.SceneManipulation +{ + /// + /// Provides methods to edit a node, that is, to change its name or type. + /// + public class GameNodeEditor + { + /// + /// Changes the name of a node. + /// + /// The node which name should be changed. + /// The new name. + public static void ChangeName(Node node, string newName) + { + node.SourceName = newName.Trim(); + if (node.GameObject() != null) + { + ShouldAddTextObject(node); + Transform transform = node.GameObject().transform; + foreach (Transform t in transform) + { + if (t.name.Contains("Text") || t.name.Contains("Label")) + { + t.GetComponent().text = newName.Trim(); + } + } + } + } + + /// + /// Changes the type of a node. + /// + /// The node which type should be changed. + /// The new type. + public static void ChangeType(Node node, string type) + { + node.Type = type; + GameObject nodeObject = node.GameObject(true); + AbstractSEECity city = nodeObject.ContainingCity(); + + ShouldAddTextObject(node); + GetText(nodeObject)?.SetActive(city.NodeTypes[node.Type].ShowNames); + + if (city.Renderer is GraphRenderer renderer) + { + renderer.AdjustStyle(nodeObject); + if (GetText(nodeObject) != null) + { + GetText(nodeObject).GetComponent().color = nodeObject.GetColor().Invert(); + } + } + } + + /// + /// Returns the text object of . This is the first child of + /// that has a component and whose + /// name contains 'Text'. + /// + /// the game object whose text object is requested + /// The text object or null if there is no such object. + private static GameObject GetText(GameObject go) + { + foreach (Transform transform in go.transform) + { + if (transform.name.Contains("Text") && transform.GetComponent() != null) + { + return transform.gameObject; + } + } + return null; + } + + /// + /// Checks if the decorations of the node needs to be added + /// and adds them if necessary. + /// + /// The node to be checked. + private static void ShouldAddTextObject(Node node) + { + if (node.GameObject().ContainingCity().NodeTypes[node.Type].ShowNames + && node.GameObject().ContainingCity().Renderer is GraphRenderer renderer + && GetText(node.GameObject()) == null + && !string.IsNullOrWhiteSpace(node.SourceName)) + { + renderer.AddDecorations(node.GameObject()); + } + } + } +} diff --git a/Assets/SEE/Net/Actions/PutOnAndFitNetAction.cs.meta b/Assets/SEE/Game/SceneManipulation/GameNodeEditor.cs.meta similarity index 83% rename from Assets/SEE/Net/Actions/PutOnAndFitNetAction.cs.meta rename to Assets/SEE/Game/SceneManipulation/GameNodeEditor.cs.meta index 4fb6792e51..e6faf36256 100644 --- a/Assets/SEE/Net/Actions/PutOnAndFitNetAction.cs.meta +++ b/Assets/SEE/Game/SceneManipulation/GameNodeEditor.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 535d025d894bb894cbfdde3140259c45 +guid: d3fc378885545bc4db11e44a170b6ac4 MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/SEE/Game/SceneManipulation/GameNodeMover.cs b/Assets/SEE/Game/SceneManipulation/GameNodeMover.cs index 362c2ca9ee..fbec5415d4 100644 --- a/Assets/SEE/Game/SceneManipulation/GameNodeMover.cs +++ b/Assets/SEE/Game/SceneManipulation/GameNodeMover.cs @@ -1,7 +1,5 @@ -using SEE.Game.Operator; -using SEE.GO; +using SEE.GO; using UnityEngine; -using UnityEngine.Assertions; namespace SEE.Game.SceneManipulation { @@ -10,11 +8,6 @@ namespace SEE.Game.SceneManipulation /// public static class GameNodeMover { - /// - /// Factor by which nodes should be scaled relative to their parents in . - /// - public const float ScalingFactor = 0.2f; - /// /// Sets the for both in the /// game-object hierarchy and in the underlying graph. If @@ -49,173 +42,55 @@ public static void SetParent(GameObject child, GameObject newParent) } /// - /// Puts on top of the roof of , - /// and scales it down, - /// assuming is true. This method makes sure that - /// will be contained within the area of the roof of . - /// - /// The will be an immediate child of in the - /// game-object hierarchy afterwards. - /// - /// Precondition: is not null. + /// Returns the new world coordinates based on so that the child + /// node with a size of would appear on top of + /// if moved there. /// - /// child to be put on - /// parent the is put on - /// Whether should be scaled down to fit into - /// - /// Additional amount of empty space that should be between - /// and in absolute world-space terms + /// + /// Keep in mind that might be hanging over if it is too big. + /// + /// the world-space scale of a node + /// the world position of a node + /// the target node's GameObject + /// additional amount of empty space on the Y-axis that should be between + /// and in absolute world-space units + /// the new world position after the correction /// - public static void PutOn(Transform child, GameObject parent, - bool scaleDown = false, float topPadding = 0.0001f) + public static Vector3 GetCoordinatesOn(Vector3 childWorldScale, Vector3 childPosition, GameObject target, float topPadding = 0.0001f) { - // This assignment must take place before we set the parent of child to null - // because a newly created node operator attempts to derive its code city. - NodeOperator nodeOperator = child.gameObject.NodeOperator(); - - // Release child from its current parent so that local position and scale - // and world-space position and scale are the same, respectively. - // The child will receive its new parent at the very end of this method. - child.SetParent(null); - - if (scaleDown) - { - // ScaleTo with animation factor = 0 has immediate effect. - nodeOperator.ScaleTo(ShrinkedWorldSpaceScale(child, parent), 0); - } - - // Where to move the child. - Vector3 targetWorldPosition = child.position; - Vector3 childWorldExtent = child.lossyScale / 2; - targetWorldPosition.y = parent.GetRoof() + childWorldExtent.y + topPadding; + Vector3 childWorldExtent = childWorldScale / 2; + childPosition.y = target.GetRoof() + childWorldExtent.y + topPadding; // Make sure mappingTarget stays within the roof of parent. { - Vector3 parentWorldExtent = parent.transform.lossyScale / 2; + Vector3 parentWorldExtent = target.WorldSpaceSize() / 2; // Fit child into x range of parent. - if (targetWorldPosition.x + childWorldExtent.x > parent.transform.position.x + parentWorldExtent.x) + if (childPosition.x + childWorldExtent.x > target.transform.position.x + parentWorldExtent.x) { // Right corner of child must not be farther than right corner of parent. - targetWorldPosition.x = parent.transform.position.x + parentWorldExtent.x - childWorldExtent.x; + childPosition.x = target.transform.position.x + parentWorldExtent.x - childWorldExtent.x; } - else if (targetWorldPosition.x - childWorldExtent.x < parent.transform.position.x - parentWorldExtent.x) + else if (childPosition.x - childWorldExtent.x < target.transform.position.x - parentWorldExtent.x) { // Left corner of child must be right from right corner of parent. - targetWorldPosition.x = parent.transform.position.x - parentWorldExtent.x + childWorldExtent.x; + childPosition.x = target.transform.position.x - parentWorldExtent.x + childWorldExtent.x; } // Fit child into z range of parent. - if (targetWorldPosition.z + childWorldExtent.z > parent.transform.position.z + parentWorldExtent.z) + if (childPosition.z + childWorldExtent.z > target.transform.position.z + parentWorldExtent.z) { // Front edge of child must not be farther than back edge of parent. - targetWorldPosition.z = parent.transform.position.z + parentWorldExtent.z - childWorldExtent.z; + childPosition.z = target.transform.position.z + parentWorldExtent.z - childWorldExtent.z; } - else if (targetWorldPosition.z - childWorldExtent.z < parent.transform.position.z - parentWorldExtent.z) + else if (childPosition.z - childWorldExtent.z < target.transform.position.z - parentWorldExtent.z) { // Front edge of child must not be before front edge of parent. - targetWorldPosition.z = parent.transform.position.z - parentWorldExtent.z + childWorldExtent.z; - } - } - - nodeOperator.MoveTo(targetWorldPosition, 0); - child.SetParent(parent.transform); - - // Returns the target world space scale of child relative to parent when child is to be put onto parent. - static Vector3 ShrinkedWorldSpaceScale(Transform child, GameObject parent) - { - // TODO: We need a strategy to scale down a node to the maximal size that is still - // fitting into the area where the nodes has been placed. - // We want to shrink only the ground area, but maintain the height. - return new Vector3(ScalingFactor * parent.transform.lossyScale.x, child.lossyScale.y, ScalingFactor * parent.transform.lossyScale.z); - } - } - - /// - /// FIXME: This is intended to become an improved version of PutOn(). - /// It is still work in progress. - /// - private static void PutOn2(Transform child, GameObject parent, bool scaleDown = false, float topPadding = 0.0001f) - { - Assert.IsNotNull(parent); - // child's parent is set to null so that we do not need to make a distinction - // between localScale and lossyScale. The child will receive its requested - // parent at the end of the method. - child.SetParent(null); - - Vector3 childExtent = child.lossyScale / 2; - Vector3 parentExtent = parent.transform.lossyScale / 2; - float parentLeftX = parent.transform.position.x - parentExtent.x; - float parentRightX = parent.transform.position.x + parentExtent.x; - float parentFrontZ = parent.transform.position.z - parentExtent.z; - float parentBackZ = parent.transform.position.z + parentExtent.z; - - // First, we will position child onto the roof of parent (and so that - // child's center is contained in the roof of parent if necessary). - - // The target position of child in word space. - Vector3 targetPosition; - - // Is the center of child enclosed in the roof rectangle of parent? - if (!(parentLeftX <= child.transform.position.x && child.transform.position.x <= parentRightX - && parentFrontZ <= child.transform.position.z && child.transform.position.z <= parentBackZ)) - { - // TODO: We need to develop a better strategy. - // child will be put at the center of parent. - targetPosition = parent.transform.position; - } - else - { - targetPosition = child.position; - } - targetPosition.y = parent.GetRoof() + childExtent.y + topPadding; - NodeOperator nodeOperator = child.gameObject.NodeOperator(); - nodeOperator.MoveTo(targetPosition, 0); - - // From now on, we assume that child's center is contained in the - // roof rectangle of parent. It will stay at its current location - // and only be shrinked so that it fits into parent. - - // Now, we will shrink child so that it is totally enclosed in parent. - if (scaleDown) - { - { - // Shrink if back edge of child is farther back than back edge of parent. - float factor = (parentBackZ - child.position.z) / childExtent.z; - if (factor < 1) - { - childExtent *= factor; - } - } - { - // Shrink if front edge of child is in front of front edge of parent. - float factor = (child.position.z - parentFrontZ) / childExtent.z; - if (factor < 1) - { - childExtent *= factor; - } + childPosition.z = target.transform.position.z - parentWorldExtent.z + childWorldExtent.z; } - { - // Shrink if left edge of child is farther left than left edge of parent. - float factor = (child.position.x - parentLeftX) / childExtent.x; - if (factor < 1) - { - childExtent *= factor; - } - } - { - // Shrink if right edge of child is farther right than right edge of parent. - float factor = (parentRightX - child.position.x) / childExtent.x; - if (factor < 1) - { - childExtent *= factor; - } - } - // ScaleTo with animation factor = 0 has immediate effect. - nodeOperator.ScaleTo(2 * childExtent, 0); } - child.SetParent(parent.transform); + return childPosition; } /// @@ -233,38 +108,6 @@ public static void NewMovementVersion(GameObject movedObject) } } - /// - /// Puts on visually. If - /// is different from , the will be scaled - /// down so that it fits into . If instead - /// and are the same, will be scaled back - /// to its . - /// - /// The will be an immediate child of in the - /// game-object hierarchy afterwards. - /// - /// Calling this method is equivalent to - /// with a previous scaling of to if - /// equals . - /// game object to be put onto - /// where to put - /// the of - /// original local scale of relative to - /// ; used to restore this scale if - /// and are the same - public static void PutOnAndFit(Transform child, GameObject newParent, - GameObject originalParent, Vector3 originalLocalScale) - { - bool scaleDown = newParent != originalParent; - if (!scaleDown) - { - // The gameObject may have already been scaled down, hence, - // we need to restore its original scale. - child.gameObject.NodeOperator().ScaleTo(originalLocalScale, 0); - } - PutOn(child, newParent, scaleDown: scaleDown); - } - /// /// Moves (assumed to represent a node) to /// through some animation. All existing animations are cancelled. diff --git a/Assets/SEE/GameObjects/GameObjectExtensions.cs b/Assets/SEE/GameObjects/GameObjectExtensions.cs index 1d732ac882..c0020ed0c9 100644 --- a/Assets/SEE/GameObjects/GameObjectExtensions.cs +++ b/Assets/SEE/GameObjects/GameObjectExtensions.cs @@ -345,7 +345,7 @@ public static void SetAbsoluteScale(this GameObject gameObject, Vector3 worldSca /// world-space y position of the roof of this public static float GetRoof(this GameObject gameObject) { - return gameObject.transform.position.y + gameObject.WorldSpaceScale().y / 2.0f; + return gameObject.transform.position.y + gameObject.WorldSpaceSize().y / 2.0f; } /// @@ -356,7 +356,7 @@ public static float GetRoof(this GameObject gameObject) public static Vector3 GetRoofCenter(this GameObject gameObject) { Vector3 result = gameObject.transform.position; - result.y += gameObject.WorldSpaceScale().y / 2.0f; + result.y += gameObject.WorldSpaceSize().y / 2.0f; return result; } @@ -368,7 +368,7 @@ public static Vector3 GetRoofCenter(this GameObject gameObject) public static Vector3 GetGroundCenter(this GameObject gameObject) { Vector3 result = gameObject.transform.position; - result.y -= gameObject.WorldSpaceScale().y / 2.0f; + result.y -= gameObject.WorldSpaceSize().y / 2.0f; return result; } @@ -435,13 +435,25 @@ public static Vector3 GetTop(this GameObject gameObject, Func f /// /// Returns the size of the given in world space. + /// + /// This is a shorthand to get the bounds.size of the component, if present. + /// This value reflects the actual world-space bounds of the cuboid that contains the rendered object. + /// + /// This value should often be used instead of the transform.lossyScale because the scale only reflects + /// the size for objects with a standardized size like cube primitives. + /// + /// Local-space counterpart: + /// /// - /// object whose size is requested + /// + /// If the game object has no renderer, its lossyScale is returned. + /// + /// object whose scale is requested /// size of given - public static Vector3 WorldSpaceScale(this GameObject gameObject) + public static Vector3 WorldSpaceSize(this GameObject gameObject) { // For some objects, such as capsules, lossyScale gives wrong results. - // The more reliable option to determine the size is using the + // The more reliable option to determine the scale is using the // object's renderer if it has one. if (gameObject.TryGetComponent(out Renderer renderer)) { @@ -454,6 +466,37 @@ public static Vector3 WorldSpaceScale(this GameObject gameObject) } } + /// + /// Returns the size of the given in local space, + /// i.e., in relation to its parent. + /// + /// This value should often be used instead of the transform.localScale because the scale only reflects + /// the size for objects with a standardized size like cube primitives. + /// + /// World-space counterpart: + /// + /// + /// + /// If the game object has no renderer, its localScale is returned. + /// + /// object whose scale is requested + /// size of given + public static Vector3 LocalSize(this GameObject gameObject) + { + // For some objects, such as capsules, localScale gives wrong results. + // The more reliable option to determine the scale is using the + // object's renderer if it has one. + if (gameObject.TryGetComponent(out Renderer renderer)) + { + return Vector3.Scale(renderer.localBounds.size, gameObject.transform.localScale); + } + else + { + // No renderer, so we use localScale as a fallback. + return gameObject.transform.localScale; + } + } + /// /// Returns true if this is within the spatial area of , /// that is, if the bounding box of plus the extra padding @@ -588,8 +631,29 @@ public static bool IsNode(this GameObject gameObject) } /// - /// Returns true if has a - /// component attached to it. + /// Returns true if 's + /// is true and it is tagged by . + /// + /// the game object to check + /// true if is an active node + public static bool IsNodeAndActiveSelf(this GameObject gameObject) + { + return gameObject.activeSelf && gameObject.CompareTag(Tags.Node); + } + + /// + /// Returns true if 's + /// is true and it is tagged by . + /// + /// the game object to check + /// true if is an active node + public static bool IsNodeAndActiveInHierarchy(this GameObject gameObject) + { + return gameObject.CompareTag(Tags.Node) && gameObject.activeInHierarchy; + } + + /// + /// Retrieves the node reference component, if possible. /// /// the game object whose NodeRef is checked /// the attached NodeRef; defined only if this method @@ -956,5 +1020,48 @@ public static GraphElementOperator Operator(this GameObject gameObject) } } } + + /// + /// Checks if overlaps with any other direct child node of its parent. + /// + /// Overlap is checked based on the Collider components. Objects with no Collider + /// component are ignored. + /// + /// + /// + /// The must be a node, i.e., coantain a NodeRef component. + /// + /// The game object whose operator to retrieve. + /// false if does not have a Collider component, + /// or does not overlap with its siblings + /// + /// Thrown when the object the method is called on is not a node, i.e., has no NodeRef + /// component. + /// + public static bool OverlapsWithSiblings(this GameObject gameObject) + { + if (!gameObject.HasNodeRef()) + { + throw new InvalidOperationException("GameObject must be a node!"); + } + if (!gameObject.TryGetComponent(out Collider collider)) + { + return false; + } + foreach (Transform sibling in gameObject.transform.parent) + { + if (sibling.gameObject == gameObject || !sibling.gameObject.HasNodeRef() || !sibling.gameObject.TryGetComponent(out Collider siblingCollider)) + { + continue; + } + + if (collider.bounds.Intersects(siblingCollider.bounds)) + { + return true; + } + } + + return false; + } } } diff --git a/Assets/SEE/GameObjects/SEESpline.cs b/Assets/SEE/GameObjects/SEESpline.cs index 55095d671b..b4c5952ee6 100644 --- a/Assets/SEE/GameObjects/SEESpline.cs +++ b/Assets/SEE/GameObjects/SEESpline.cs @@ -22,8 +22,8 @@ namespace SEE.GO /// ), the internal state is marked dirty and the /// rendering is updated in the next frame (via ). /// There are two rendering methods: - /// - /// 1. : The spline is rendered as polyline. + /// + /// : The spline is rendered as polyline. /// This method is comparatively fast, but lacks more advanced features /// such as collision detection. It serves as a placeholder until the /// runtime environment found the time to create a @@ -31,15 +31,15 @@ namespace SEE.GO /// etc.). This class doesn't create /// instances on its own, but rather updates /// them if they are present. - /// - /// 2. : The spline is rendered as tubular mesh. This + /// + /// : The spline is rendered as tubular mesh. This /// method is a lot slower than , but in /// contrast creates "real" 3D objects with collision detection. Because /// the creation of a larger amount of meshes is quite slow, it is up to /// an external client to replace any with a /// . For this purpose there is the method /// . - /// + /// /// The geometric characteristics of the generated mesh, e.g., the radius /// of the tube, can be set via properties. By setting a property, the /// rendering of the spline is updated in the next frame. If an update @@ -84,6 +84,11 @@ public class SEESpline : SerializedMonoBehaviour [SerializeField] private float subsplineEndT = 1.0f; + /// + /// The event is emitted each time the renderer is updated (see ). + /// + public event Action OnRendererChanged; + /// /// Property of . /// @@ -303,6 +308,7 @@ private void Update() UpdateLineRenderer(); UpdateMesh(); needsUpdate = needsColorUpdate = false; + OnRendererChanged?.Invoke(); } else if (needsColorUpdate) { @@ -348,8 +354,7 @@ private void UpdateLineRenderer() { if (gameObject.TryGetComponent(out LineRenderer lr)) { - BSpline subSpline = CreateSubSpline(); - Vector3[] polyLine = TinySplineInterop.ListToVectors(subSpline.Sample()); + Vector3[] polyLine = GenerateVertices(); lr.positionCount = polyLine.Length; lr.SetPositions(polyLine); @@ -359,6 +364,16 @@ private void UpdateLineRenderer() needsUpdate = false; } + /// + /// Generates the vertices that represent this spline. + /// + /// The vertices that make up this spline. + public Vector3[] GenerateVertices() + { + BSpline subSpline = CreateSubSpline(); + return TinySplineInterop.ListToVectors(subSpline.Sample()); + } + /// /// Updates the start and end color of the line renderer attached /// to the gameObject using the values of diff --git a/Assets/SEE/GraphProviders/AllGitBranchesSingleGraphProvider.cs b/Assets/SEE/GraphProviders/AllGitBranchesSingleGraphProvider.cs index 5c4bb57ba4..7b4a5e036e 100644 --- a/Assets/SEE/GraphProviders/AllGitBranchesSingleGraphProvider.cs +++ b/Assets/SEE/GraphProviders/AllGitBranchesSingleGraphProvider.cs @@ -52,7 +52,7 @@ public class AllGitBranchesSingleGraphProvider : SingleGraphProvider Tooltip("Path globbings and whether they are inclusive (true) or exclusive (false)."), RuntimeTab(GraphProviderFoldoutGroup), HideReferenceObjectPicker] - public Dictionary PathGlobbing = new Dictionary() + public Dictionary PathGlobbing = new() { { "**/*", true } }; @@ -79,7 +79,7 @@ public class AllGitBranchesSingleGraphProvider : SingleGraphProvider /// /// The interval in seconds in which git fetch should be called. /// - [Tooltip("The interval in seconds in which the repositor should be polled. Used only if Auto Fetch is true."), + [Tooltip("The interval in seconds in which the repository should be polled. Used only if Auto Fetch is true."), EnableIf(nameof(AutoFetch)), Range(5, 200)] public int PollingInterval = 5; diff --git a/Assets/SEE/Net/Actions/DeleteNetAction.cs b/Assets/SEE/Net/Actions/DeleteNetAction.cs index e27945320f..c332e89131 100644 --- a/Assets/SEE/Net/Actions/DeleteNetAction.cs +++ b/Assets/SEE/Net/Actions/DeleteNetAction.cs @@ -42,7 +42,9 @@ public override void ExecuteOnServer() public override void ExecuteOnClient() { GameObject gameObject = GraphElementIDMap.Find(GameObjectID, mustFindElement: true); +#pragma warning disable VSTHRD110 GameElementDeleter.Delete(gameObject); +#pragma warning restore VSTHRD110 } } } diff --git a/Assets/SEE/Net/Actions/EditNodeNetAction.cs b/Assets/SEE/Net/Actions/EditNodeNetAction.cs index b399ad49a1..38f2eef930 100644 --- a/Assets/SEE/Net/Actions/EditNodeNetAction.cs +++ b/Assets/SEE/Net/Actions/EditNodeNetAction.cs @@ -1,5 +1,6 @@ using SEE.DataModel.DG; using SEE.Game; +using SEE.Game.SceneManipulation; using SEE.GO; using UnityEngine; @@ -54,8 +55,8 @@ public override void ExecuteOnServer() public override void ExecuteOnClient() { Node node = Find(NodeID).GetNode(); - node.SourceName = SourceName; - node.Type = NodeType; + GameNodeEditor.ChangeName(node, SourceName); + GameNodeEditor.ChangeType(node, NodeType); } } } diff --git a/Assets/SEE/Net/Actions/PutOnAndFitNetAction.cs b/Assets/SEE/Net/Actions/PutOnAndFitNetAction.cs deleted file mode 100644 index c33070d426..0000000000 --- a/Assets/SEE/Net/Actions/PutOnAndFitNetAction.cs +++ /dev/null @@ -1,76 +0,0 @@ -using SEE.Game; -using SEE.Game.SceneManipulation; -using UnityEngine; - -namespace SEE.Net.Actions -{ - /// - /// Propagates through the network. - /// - internal class PutOnAndFitNetAction : AbstractNetAction - { - /// - /// The unique name of the child gameObject that needs to be put onto a new parent. - /// Must be known to . - /// - public string ChildID; - - /// - /// The unique name of the gameObject that becomes the new parent of the child. - /// Must be known to . - /// - public string NewParentID; - - /// - /// The unique name of the gameObject that was the original parent of the child. - /// Must be known to . - /// - public string OriginalParentID; - - /// - /// The original scale of the child relative to its original parent (local scale). - /// - public Vector3 OriginalLocalScale; - - /// - /// Constructor. - /// - /// the unique game-object name of the game object of the child to - /// be put and fit onto the ; - /// must be known to - /// the unique game-object name of the game object becoming the - /// new parent of ; - /// must be known to - /// the unique name of the gameObject that was the original - /// parent of the child; - /// must be known to . - /// the original local scale of - /// relative to - public PutOnAndFitNetAction(string childID, string newParentID, string originalParentID, Vector3 originalLocalScale) - { - ChildID = childID; - NewParentID = newParentID; - OriginalParentID = originalParentID; - OriginalLocalScale = originalLocalScale; - } - - /// - /// Movement in all clients except the requesting client. - /// - public override void ExecuteOnClient() - { - GameObject child = Find(ChildID); - GameObject newParent = Find(NewParentID); - GameObject originalParent = Find(OriginalParentID); - GameNodeMover.PutOnAndFit(child.transform, newParent, originalParent, OriginalLocalScale); - } - - /// - /// Does not do anything. - /// - public override void ExecuteOnServer() - { - // Intentionally left blank. - } - } -} diff --git a/Assets/SEE/Net/Actions/ResizeNodeNetAction.cs b/Assets/SEE/Net/Actions/ResizeNodeNetAction.cs new file mode 100644 index 0000000000..375bffa331 --- /dev/null +++ b/Assets/SEE/Net/Actions/ResizeNodeNetAction.cs @@ -0,0 +1,72 @@ +using SEE.GO; +using UnityEngine; + +namespace SEE.Net.Actions +{ + /// + /// Propagates changed size and position of a single game node through the network. + /// + /// Children are not scaled or moved along with the resized node. + /// + /// + public class ResizeNodeNetAction : AbstractNetAction + { + /// + /// The id of the gameObject that has to be resized. + /// + public string GameObjectID; + + /// + /// The new local scale to transfer over the network. + /// + public Vector3 LocalScale; + + /// + /// The new world-space position to transfer over the network. + /// + public Vector3 Position; + + /// + /// Should the edges be updated along with the targe node? + /// + public bool UpdateEdges; + + /// + /// Should the child nodes keep their size? + /// + public bool ReparentChildren; + + /// + /// Constructs a . + /// + /// The unique name of the that should be resized + /// The new local scale of the + /// The new world-space position of the + /// if true, the children are not moved and scaled along with their parent + /// if true, the connecting edges will be moved along with the node + public ResizeNodeNetAction(string gameObjectID, Vector3 localScale, Vector3 position, bool updateEdges = true, bool reparentChildren = true) + { + GameObjectID = gameObjectID; + LocalScale = localScale; + Position = position; + UpdateEdges = updateEdges; + ReparentChildren = reparentChildren; + } + + /// + /// Finds the GameObject on the client and sets its scale. + /// + public override void ExecuteOnClient() + { + GameObject go = Find(GameObjectID); + if (go != null) + { + go.NodeOperator().ResizeTo(LocalScale, Position, factor: 1, UpdateEdges, ReparentChildren); + } + else + { + throw new System.Exception($"There is no game object with the ID {GameObjectID}."); + } + } + } +} diff --git a/Assets/SEE/Net/Actions/ResizeNodeNetAction.cs.meta b/Assets/SEE/Net/Actions/ResizeNodeNetAction.cs.meta new file mode 100644 index 0000000000..2cabc4ff00 --- /dev/null +++ b/Assets/SEE/Net/Actions/ResizeNodeNetAction.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 202a53012045be647b8ce6642276bee3 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SEE/Net/Actions/ZoomNetAction.cs b/Assets/SEE/Net/Actions/ZoomNetAction.cs deleted file mode 100644 index c3180dbc86..0000000000 --- a/Assets/SEE/Net/Actions/ZoomNetAction.cs +++ /dev/null @@ -1,69 +0,0 @@ -using SEE.Controls.Actions; -using SEE.Game; -using SEE.Game.Operator; -using SEE.GO; -using SEE.Utils; -using UnityEngine; - -namespace SEE.Net.Actions -{ - /// - /// Propagates the zooming of a game node through the network. - /// - internal class ZoomNetAction : AbstractNetAction - { - /// - /// The unique name of the gameObject of a node that needs to be moved. - /// - public string GameObjectID; - - /// - /// Where the game object should be placed in world space. - /// - public Vector3 Position; - - /// - /// The local scale of the game object after the zooming. - /// - public Vector3 LocalScale; - - /// - /// Constructor. - /// - /// the unique game-object name of the game object to be moved - /// the new position of the game object - /// the new local scale of the game object - public ZoomNetAction(string gameObjectID, Vector3 position, Vector3 localScale) - { - GameObjectID = gameObjectID; - Position = position; - LocalScale = localScale; - } - - /// - /// Zooming in all clients except the requesting client. - /// - public override void ExecuteOnClient() - { - GameObject gameObject = GraphElementIDMap.Find(GameObjectID); - if (gameObject != null) - { - NodeOperator nodeOperator = gameObject.NodeOperator(); - nodeOperator.MoveTo(Position, ZoomAction.AnimationFactor); - nodeOperator.ScaleTo(LocalScale, ZoomAction.AnimationFactor); - } - else - { - throw new System.Exception($"There is no game object with the ID {GameObjectID}."); - } - } - - /// - /// Does not do anything. - /// - public override void ExecuteOnServer() - { - // Intentionally left blank. - } - } -} diff --git a/Assets/SEE/SEE.asmdef b/Assets/SEE/SEE.asmdef index 9eb9289ac1..63d900fb59 100644 --- a/Assets/SEE/SEE.asmdef +++ b/Assets/SEE/SEE.asmdef @@ -69,7 +69,8 @@ "System.Collections.Immutable.dll", "MoreLinq.dll", "Microsoft.Extensions.FileSystemGlobbing.dll", - "MediatR.dll" + "MediatR.dll", + "MediatR.Contracts.dll" ], "autoReferenced": false, "defineConstraints": [], diff --git a/Assets/SEE/UI/Drawable/DrawableActionBar.cs b/Assets/SEE/UI/Drawable/DrawableActionBar.cs index e87ccde24c..986a5faada 100644 --- a/Assets/SEE/UI/Drawable/DrawableActionBar.cs +++ b/Assets/SEE/UI/Drawable/DrawableActionBar.cs @@ -65,7 +65,8 @@ void Start() /// void Update() { - if (GlobalActionHistory.Current().Parent == ActionStateTypes.Drawable) + if (GlobalActionHistory.Current() != null + && GlobalActionHistory.Current().Parent == ActionStateTypes.Drawable) { barInstance.SetActive(true); togglerInstance.SetActive(false); diff --git a/Assets/SEE/UI/HelpSystem/HelpSystemEntry.cs b/Assets/SEE/UI/HelpSystem/HelpSystemEntry.cs index 267398be73..c792236477 100644 --- a/Assets/SEE/UI/HelpSystem/HelpSystemEntry.cs +++ b/Assets/SEE/UI/HelpSystem/HelpSystemEntry.cs @@ -47,12 +47,16 @@ internal class HelpSystemEntry : PlatformDependentComponent public bool IsPlaying { get; set; } /// - /// Path to the HelpSystemEntry prefab. + /// Path to the HelpSystemEntry prefab. It contains the video player, + /// the text area for the help text, and the buttons for controlling the video + /// as well as the button to close the dialog and the button to go back to the + /// parent in the help menu. /// private const string helpSystemEntryPrefab = "Prefabs/UI/HelpSystemEntry"; /// - /// Path to the HelpSystemEntrySpace prefab. + /// Path to the HelpSystemEntrySpace prefab. It is a panel in which + /// the HelpSystemEntry is placed. /// private const string helpSystemEntrySpacePrefab = "Prefabs/UI/HelpSystemEntrySpace"; @@ -96,13 +100,17 @@ internal class HelpSystemEntry : PlatformDependentComponent private ButtonManagerBasicIcon backwardButton; /// - /// The helpSystemEntry-GameObject. + /// The helpSystemEntry GameObject. + /// It will be instantiated from the prefab . + /// It will be a child of . /// private GameObject helpSystemEntry; /// /// The helpSystemEntrySpace-GameObject which contains the helpSystemEntry. /// It is nessecary because of the dynamic panel for scaling the entry. + /// It will be instantiated from the prefab . + /// It will be a child of . /// private GameObject helpSystemSpace; @@ -141,13 +149,25 @@ protected override void StartDesktop() { /// Note: called below accesses /// that is why we need to instantiate it first. - helpSystemSpace = PrefabInstantiator.InstantiatePrefab(helpSystemEntrySpacePrefab, Canvas.transform, false); + SetUpHelpSystemEntryAndSpace(); helpSystemSpace.SetActive(false); - helpSystemEntry = PrefabInstantiator.InstantiatePrefab(helpSystemEntryPrefab, helpSystemSpace.transform, false); helpSystemEntry.SetActive(false); instructionsDisplay = GetTextField(); } + /// + /// Instantiates the help system entry and the space if necessary, that is, + /// if is null. + /// + private void SetUpHelpSystemEntryAndSpace() + { + if (helpSystemSpace == null) + { + helpSystemSpace = PrefabInstantiator.InstantiatePrefab(helpSystemEntrySpacePrefab, Canvas.transform, false); + helpSystemEntry = PrefabInstantiator.InstantiatePrefab(helpSystemEntryPrefab, helpSystemSpace.transform, false); + } + } + /// /// Returns the game object holding a TextMeshPro component in which the instructions /// are printed. It is the descendant of with the @@ -249,6 +269,9 @@ public VideoPlayer GetVideoPlayer() /// public void ShowEntry() { + /// If the dialog was closed, and + /// are null and need to be instantiated again. + SetUpHelpSystemEntryAndSpace(); helpSystemSpace.SetActive(true); helpSystemEntry.SetActive(true); helpSystemSpace.transform.localScale = new Vector3(1.7f, 1.7f); diff --git a/Assets/SEE/UI/Menu/Drawable/ConfirmDialogMenu.cs b/Assets/SEE/UI/Menu/Drawable/ConfirmDialogMenu.cs index ce40e51fea..351ac13719 100644 --- a/Assets/SEE/UI/Menu/Drawable/ConfirmDialogMenu.cs +++ b/Assets/SEE/UI/Menu/Drawable/ConfirmDialogMenu.cs @@ -1,6 +1,9 @@ -using Michsky.UI.ModernUIPack; +using Cysharp.Threading.Tasks; +using Michsky.UI.ModernUIPack; using SEE.Game.Drawable; +using SEE.Utils; using TMPro; +using UnityEngine.Events; namespace SEE.UI.Menu.Drawable { @@ -18,37 +21,48 @@ public class ConfirmDialogMenu : Menu /// Enables the dialog menu with given /// /// The text that should be displayed. - public void Enable(string text) + public ConfirmDialogMenu(string text) { - if (gameObject == null) + Instantiate(confirmMenuPrefab); + + /// Initialize the buttons. + ButtonManagerBasic cancelDragger = GameFinder.FindChild(gameObject, "CancelDragger") + .GetComponent(); + cancelDragger.clickEvent.AddListener(() => + { + WasCanceled = true; + Destroyer.Destroy(gameObject); + }); + ButtonManagerBasic confirm = GameFinder.FindChild(gameObject, "Confirm") + .GetComponent(); + confirm.clickEvent.AddListener(() => + { + WasConfirmed = true; + Destroyer.Destroy(gameObject); + }); + ButtonManagerBasic cancel = GameFinder.FindChild(gameObject, "Cancel") + .GetComponent(); + cancel.clickEvent.AddListener(() => { - Instantiate(confirmMenuPrefab); + WasCanceled = true; + Destroyer.Destroy(gameObject); + }); + TextMeshProUGUI description = GameFinder.FindChild(gameObject, "Description") + .GetComponent(); + description.text = text; + } - /// Initialize the buttons. - ButtonManagerBasic cancelDragger = GameFinder.FindChild(gameObject, "CancelDragger") - .GetComponent(); - cancelDragger.clickEvent.AddListener(() => - { - WasCanceled = true; - Destroy(); - }); - ButtonManagerBasic confirm = GameFinder.FindChild(gameObject, "Confirm") - .GetComponent(); - confirm.clickEvent.AddListener(() => - { - WasConfirmed = true; - Destroy(); - }); - ButtonManagerBasic cancel = GameFinder.FindChild(gameObject, "Cancel") - .GetComponent(); - cancel.clickEvent.AddListener(() => - { - WasCanceled = true; - Destroy(); - }); - TextMeshProUGUI description = GameFinder.FindChild(gameObject, "Description") - .GetComponent(); - description.text = text; + /// + /// Executes the action after confirming the dialog. + /// + /// The action to be executed. + /// nothing, it waits until the dialog was confirmed or canceled. + public async UniTask ExecuteAfterConfirmAsync(UnityAction action) + { + await UniTask.WaitWhile(IsOpen); + if (WasConfirmed && !WasCanceled) + { + action.Invoke(); } } diff --git a/Assets/SEE/UI/PopupMenu/PopupMenu.cs b/Assets/SEE/UI/PopupMenu/PopupMenu.cs index 708316d63b..91d70658b1 100644 --- a/Assets/SEE/UI/PopupMenu/PopupMenu.cs +++ b/Assets/SEE/UI/PopupMenu/PopupMenu.cs @@ -1,9 +1,11 @@ -using System.Collections.Generic; using Cysharp.Threading.Tasks; using DG.Tweening; using Michsky.UI.ModernUIPack; using SEE.GO; using SEE.Utils; +using System; +using System.Collections.Generic; +using System.Linq; using TMPro; using UnityEngine; using UnityEngine.UI; @@ -70,13 +72,32 @@ public class PopupMenu : PlatformDependentComponent /// /// The height of the menu. /// - private float MenuHeight => menu.sizeDelta.y; + private float MenuHeight => GetHeight(); + + /// + /// The width of the menu. + /// + private float MenuWidth => menu.sizeDelta.x; /// /// Duration of the animation that is used to show or hide the menu. /// private const float animationDuration = 0.5f; + /// + /// The popup entries. + /// + private readonly List entries = new(); + + /// + /// Gets the height of the menu. + /// + /// The current height. + private float GetHeight() + { + return entries.Sum(x => ((RectTransform) x.transform).rect.height); + } + protected override void StartDesktop() { // Instantiate the menu. @@ -122,6 +143,9 @@ public void AddEntry(PopupMenuEntry entry) switch (entry) { + case PopupMenuActionDoubleIcon doubleIconAction: + AddDoubleIconAction(doubleIconAction); + break; case PopupMenuAction action: AddAction(action); break; @@ -131,25 +155,31 @@ public void AddEntry(PopupMenuEntry entry) default: throw new System.ArgumentException($"Unknown entry type: {entry.GetType()}"); } - - // TODO (#668): Respect priority } /// /// Adds a new to the menu. /// /// The action to be added. - private void AddAction(PopupMenuAction action) + /// The item to be added to the PopupMenu. + /// If the default item is to be added, null should be used. + /// Another item can be, for example, the SubMenuButton. + /// + private void AddAction(PopupMenuAction action, GameObject actionItem = null) { - GameObject actionItem = PrefabInstantiator.InstantiatePrefab("Prefabs/UI/PopupMenuButton", actionList, false); + actionItem ??= PrefabInstantiator.InstantiatePrefab("Prefabs/UI/PopupMenuButton", actionList, false); ButtonManagerBasic button = actionItem.MustGetComponent(); button.buttonText = action.Name; + PriorityHolder priorityHolder = actionItem.AddComponent(); + priorityHolder.Priority = action.Priority; + button.clickEvent.AddListener(OnClick); if (action.IconGlyph != default) { actionItem.transform.Find("Icon").gameObject.MustGetComponent().text = action.IconGlyph.ToString(); } + entries.Add(actionItem); return; void OnClick() @@ -162,6 +192,22 @@ void OnClick() } } + /// + /// Adds a new to the menu. + /// It can be used for popup sub-menus. + /// + /// The sub-menu to be added. + private void AddDoubleIconAction(PopupMenuActionDoubleIcon doubleIconAction) + { + GameObject actionItem = PrefabInstantiator.InstantiatePrefab("Prefabs/UI/PopupMenuSubMenuButton", actionList, false); + if (doubleIconAction.RightIconGlyph != default) + { + actionItem.transform.Find("RightIcon").gameObject.MustGetComponent() + .text = doubleIconAction.RightIconGlyph.ToString(); + } + AddAction(doubleIconAction, actionItem); + } + /// /// Adds a new to the menu. /// @@ -171,6 +217,9 @@ private void AddHeading(PopupMenuHeading heading) GameObject headingItem = PrefabInstantiator.InstantiatePrefab("Prefabs/UI/PopupMenuHeading", actionList, false); TextMeshProUGUI text = headingItem.MustGetComponent(); text.text = heading.Text; + PriorityHolder priorityHolder = headingItem.AddComponent(); + priorityHolder.Priority = heading.Priority; + entries.Add(headingItem); } /// @@ -195,11 +244,11 @@ public void ClearEntries() entriesBeforeStart.Clear(); return; } - - foreach (Transform child in actionList) + foreach (GameObject entry in entries) { - Destroyer.Destroy(child.gameObject); + Destroyer.Destroy(entry); } + entries.Clear(); } /// @@ -209,15 +258,19 @@ public void ClearEntries() public void MoveTo(Vector2 position) { AdjustMenuHeight(); + bool moved = false; if (position.y < MenuHeight * ScaleFactor) { // If the menu is too close to the bottom of the screen, expand it upwards instead. - position.y += MenuHeight * ScaleFactor; - // The mouse should hover over the first menu item already rather than being just outside of it, - // so we move the menu down and to the left a bit. - position += new Vector2(-5, -5); + position.y = MenuHeight * ScaleFactor; + moved = true; + } + if (Screen.width < position.x + MenuWidth * ScaleFactor) + { + position.x = Screen.width - MenuWidth * ScaleFactor; + moved = true; } - else + if (!moved) { // The mouse should hover over the first menu item already rather than being just outside of it, // so we move the menu up and to the left a bit. @@ -233,10 +286,32 @@ public void MoveTo(Vector2 position) private void AdjustMenuHeight() { // Menu should not take up more than 40% of the screen. - float height = Mathf.Clamp(actionList.sizeDelta.y, 100f, Screen.height / (2.5f*ScaleFactor)); + float height = Mathf.Clamp(MenuHeight, 100f, Screen.height / (2.5f * ScaleFactor)); scrollView.sizeDelta = new Vector2(scrollView.sizeDelta.x, height); } + /// + /// Sorts the entries by their priority. + /// Keep in mind: A higher priority is displayed first. + /// + private void SortEntries() + { + entries.Sort((a, b) => + { + PriorityHolder aHolder = a.GetComponent(); + PriorityHolder bHolder = b.GetComponent(); + if (aHolder == null || bHolder == null) + { + return 0; + } + return bHolder.Priority.CompareTo(aHolder.Priority); + }); + for (int i = 0; i < entries.Count; i++) + { + entries[i].transform.SetSiblingIndex(i); + } + } + /// /// Activates the menu and fades it in. /// This asynchronous method will return once the menu is fully shown. @@ -253,6 +328,7 @@ public async UniTask ShowMenuAsync() await UniTask.WaitForEndOfFrame(); contentSizeFitter.enabled = true; AdjustMenuHeight(); + SortEntries(); await UniTask.WhenAll(menu.DOScale(1, animationDuration).AsyncWaitForCompletion().AsUniTask(), menuCanvasGroup.DOFade(1, animationDuration / 2).AsyncWaitForCompletion().AsUniTask()); } diff --git a/Assets/SEE/UI/PopupMenu/PopupMenuEntry.cs b/Assets/SEE/UI/PopupMenu/PopupMenuEntry.cs index a40808e7d2..1977ea9047 100644 --- a/Assets/SEE/UI/PopupMenu/PopupMenuEntry.cs +++ b/Assets/SEE/UI/PopupMenu/PopupMenuEntry.cs @@ -1,5 +1,4 @@ using System; -using UnityEngine.Events; namespace SEE.UI.PopupMenu { @@ -21,7 +20,7 @@ public abstract record PopupMenuEntry(int Priority); /// The priority of the entry. Entries with a higher priority /// are displayed first. public record PopupMenuAction(string Name, Action Action, char IconGlyph, bool CloseAfterClick = true, - int Priority = default) : PopupMenuEntry(Priority); + int Priority = default) : PopupMenuEntry(Priority); /// /// A heading that can be added to a . @@ -30,4 +29,19 @@ public record PopupMenuAction(string Name, Action Action, char IconGlyph, bool C /// The priority of the entry. Entries with a higher priority /// are displayed first. public record PopupMenuHeading(string Text, int Priority = default) : PopupMenuEntry(Priority); + + /// + /// A sub menu action that can be added to a . + /// + /// The name of the action. + /// The action to be executed when the user clicks on the action. + /// The unicode glyph of the FontAwesome v6 icon + /// that should be displayed left of the . + /// The unicode glyph of the FontAwesome v6 icon + /// that should be displayed right of the . + /// Whether the menu should be closed after the action is executed. + /// The priority of the entry. Entries with a higher priority + /// are displayed first. + public record PopupMenuActionDoubleIcon(string Name, Action Action, char LeftIconGlyph, char RightIconGlyph, + bool CloseAfterClick = true, int Priority = default) : PopupMenuAction(Name, Action, LeftIconGlyph, CloseAfterClick, Priority); } diff --git a/Assets/SEE/UI/PopupMenu/PriorityHolder.cs b/Assets/SEE/UI/PopupMenu/PriorityHolder.cs new file mode 100644 index 0000000000..60ad2db2f5 --- /dev/null +++ b/Assets/SEE/UI/PopupMenu/PriorityHolder.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +namespace SEE.UI.PopupMenu +{ + /// + /// Component which holds the priority of a . + /// + public class PriorityHolder : MonoBehaviour + { + /// + /// The priority of a . + /// + public int Priority { get; set; } = 0; + } +} diff --git a/Assets/SEE/UI/PopupMenu/PriorityHolder.cs.meta b/Assets/SEE/UI/PopupMenu/PriorityHolder.cs.meta new file mode 100644 index 0000000000..1ad6503a2a --- /dev/null +++ b/Assets/SEE/UI/PopupMenu/PriorityHolder.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: c12d1a37675d8ee4dbcac6733d44a20d +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/SEE/UI/PropertyDialog/NodePropertyDialog.cs b/Assets/SEE/UI/PropertyDialog/NodePropertyDialog.cs index ae1133f7c0..e626bffc20 100644 --- a/Assets/SEE/UI/PropertyDialog/NodePropertyDialog.cs +++ b/Assets/SEE/UI/PropertyDialog/NodePropertyDialog.cs @@ -1,6 +1,11 @@ using SEE.Controls; +using SEE.Controls.Actions; /// Reference in comment. using SEE.DataModel.DG; +using SEE.Game.SceneManipulation; +using SEE.GO; +using SEE.Net.Actions; using SEE.Utils; +using System.Linq; using UnityEngine; using UnityEngine.Events; @@ -49,12 +54,18 @@ public NodePropertyDialog(Node node) /// /// The dialog property for the type of the node to be entered in the dialog. /// - private StringProperty nodeType; + private SelectionProperty nodeType; + + /// + /// The last chosen node type for the mode. + /// + private static string lastUsed = string.Empty; /// /// Creates and opens the dialog. /// - public void Open() + /// Whether the last used index should be used and updated. + public void Open(bool useLastUsed = false) { dialog = new GameObject("Node attributes"); @@ -65,9 +76,22 @@ public void Open() nodeName.Description = "Name of the node"; // Type of the node - nodeType = dialog.AddComponent(); + nodeType = dialog.AddComponent(); nodeType.Name = "Node type"; - nodeType.Value = node.Type; + nodeType.AddOptions(node.GameObject().ContainingCity().NodeTypes.Types.OrderBy(t => t)); + if (!useLastUsed || string.IsNullOrEmpty(lastUsed)) + { + nodeType.Value = node.Type; + } + else if (useLastUsed) + { + if (node.Type != lastUsed) + { + GameNodeEditor.ChangeType(node, lastUsed); + new EditNodeNetAction(node.ID, node.SourceName, lastUsed).Execute(); + } + nodeType.Value = lastUsed; + } nodeType.Description = "Type of the node"; // Group for node name and type @@ -89,6 +113,25 @@ public void Open() SEEInput.KeyboardShortcutsEnabled = false; // Go online propertyDialog.DialogShouldBeShown = true; + + /// + /// Sets the attributes of to the trimmed values entered in the dialog, + /// notifies all listeners on , and closes the dialog. + /// + void OKButtonPressed() + { + GameNodeEditor.ChangeName(node, nodeName.Value); + GameNodeEditor.ChangeType(node, nodeType.Value); + + /// Updates the attribute. + if (useLastUsed) + { + lastUsed = nodeType.Value; + } + OnConfirm.Invoke(); + SEEInput.KeyboardShortcutsEnabled = true; + Close(); + } } /// @@ -101,19 +144,6 @@ private void CancelButtonPressed() Close(); } - /// - /// Sets the attributes of to the trimmed values entered in the dialog, - /// notifies all listeners on , and closes the dialog. - /// - private void OKButtonPressed() - { - node.SourceName = nodeName.Value.Trim(); - node.Type = nodeType.Value.Trim(); - OnConfirm.Invoke(); - SEEInput.KeyboardShortcutsEnabled = true; - Close(); - } - /// /// Destroys . will be null afterwards. /// diff --git a/Assets/SEE/UI/Window/BaseWindow.cs b/Assets/SEE/UI/Window/BaseWindow.cs index c7308ca5fb..9c9f4d6c6b 100644 --- a/Assets/SEE/UI/Window/BaseWindow.cs +++ b/Assets/SEE/UI/Window/BaseWindow.cs @@ -73,11 +73,13 @@ protected override void StartDesktop() // Set title Window.transform.Find("Dragger/Title").gameObject.GetComponent().text = Title; - // TODO: Disable IDE Button if unused + /// Disables the window dragger IDE buttons. + /// Note: If a sub class needs the IDE buttons, call + DisableWindowDraggerButtons(); } /// - /// Disables all window dragger buttons. + /// Disables the window dragger buttons. /// dd public void DisableWindowDraggerButtons() { @@ -88,6 +90,18 @@ public void DisableWindowDraggerButtons() } } + /// + /// Activates the window dragger buttons. + /// + public void ActivateWindowDraggerButtons() + { + Button[] buttons = Window.transform.Find("Dragger").GetComponentsInChildren