mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-23 15:33:26 +08:00
Merge pull request #2 from efroemling/main
big toolbar-mode UI revamp work in progress
This commit is contained in:
commit
cf02059b60
126
.efrocachemap
generated
126
.efrocachemap
generated
@ -421,43 +421,43 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55",
|
||||
"build/assets/ba_data/data/langdata.json": "99ad02cbe90ab3e46168ddf277633c68",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "dcb913b3d89fe665adbf35e697d2e5d0",
|
||||
"build/assets/ba_data/data/langdata.json": "65b989c0d893d8981992f66ff81a8a97",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "3be73283cb8009cc2c95e53df36e8b86",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "3d5523d0004293aa2df02f3f6f3b84f8",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "d4a89bf007a0624c6852c512d1d38cdc",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "319565f8a15667488f48dbce59278e39",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "fc69790c41e6750d20a7719afc5a7527",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "86671be47e2b5d0badeb3b90a3db6402",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "b23619cb396ac16640c47458f884b16a",
|
||||
"build/assets/ba_data/data/languages/czech.json": "61bcfce75c0d53d2f2af709cee42187a",
|
||||
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "b0900d572c9141897d53d6574c471343",
|
||||
"build/assets/ba_data/data/languages/english.json": "eae3a17af2efc2388f96c1e05c024455",
|
||||
"build/assets/ba_data/data/languages/english.json": "5a73dea22df1117d58a79459def62ff5",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "fabaedeefc28cf02ec365ef37046ec0b",
|
||||
"build/assets/ba_data/data/languages/french.json": "b7d11199756f0eb4f1a745ceee652b2a",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "a291d4d3619adc82c5c4096bbfefe28a",
|
||||
"build/assets/ba_data/data/languages/french.json": "73a01df9b44b3fb030750a1b5f56f07b",
|
||||
"build/assets/ba_data/data/languages/german.json": "198b9860c5b9df7b8e3e30b03d8755cb",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "085f438ccdb7553bbb7cf5d68e9cd300",
|
||||
"build/assets/ba_data/data/languages/greek.json": "ad3c0d38f34d809824892d6f22808dbf",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "d6810f99fc9055b5203c382a83bc5128",
|
||||
"build/assets/ba_data/data/languages/greek.json": "d28d1092fbb00ed857cbd53124c0dc78",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "54cd56bade6922b40989a8ac5e0c17f6",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "0cf994bf9fedf004c9a1011bee179a07",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "3a974ea6e6ffccca41aed308ad5a7a26",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "ed9038bf4b9216f93eb73e753e162706",
|
||||
"build/assets/ba_data/data/languages/italian.json": "017f2b20584838d9f5ad88822a4caf62",
|
||||
"build/assets/ba_data/data/languages/italian.json": "ffc58952260b63fdf88805a2d9a68257",
|
||||
"build/assets/ba_data/data/languages/korean.json": "4e3524327a0174250aff5e1ef4c0c597",
|
||||
"build/assets/ba_data/data/languages/malay.json": "f6ce0426d03a62612e3e436ed5d1be1f",
|
||||
"build/assets/ba_data/data/languages/persian.json": "87f9dfc085f0ff715b17a8082fc79483",
|
||||
"build/assets/ba_data/data/languages/polish.json": "3ce5635118b34ea89d6e0f83c8c7e9df",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "0accd9462f0acbc5f869f33a2a7a24cd",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "ef68520f749cf3641d4e4225a6166349",
|
||||
"build/assets/ba_data/data/languages/russian.json": "e7b90ce1eee8247e164ed7d1470f76bd",
|
||||
"build/assets/ba_data/data/languages/persian.json": "ededb9c015afb58b1324a096ea740f72",
|
||||
"build/assets/ba_data/data/languages/polish.json": "62b56ace320191985689bfbcfacd56ea",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "2be5c25e55946197bd0e0f646d444b2c",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "55a8744e466801013ea131266a856924",
|
||||
"build/assets/ba_data/data/languages/russian.json": "c7c5bfc6f82d74e49ac746d187314ba7",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "3c08c748c96c71bd9e1d7291fb8817b6",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "63f80b2c37a1d8092304db1a10ecf789",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "4b262447f703eb4c6683b54af6b7b592",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "b9fcc523639f55e05c7f4e7914f3321a",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "5ececa2dde2bbe33ad61e580fa5b79ad",
|
||||
"build/assets/ba_data/data/languages/thai.json": "1d665629361f302693dead39de8fa945",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "60691e93b58e1612901e8558b967697b",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "6207f0e4048f9391526321d879a5d61e",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "9bb01eea11d1627c0ceb876d26d86d0c",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "4bc1ba96ef291fed6d6409ad8cf7357f",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "1c0a5c0c0c115107fb0752c92907f584",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "23a98e5722d3e71e809a8a0063daa603",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "a1315f5233ebbee1464683ac55d5d9d5",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "5ae84265600b6cfda45c9bed18724e1d",
|
||||
"build/assets/ba_data/data/maps/big_g.json": "1dd301d490643088a435ce75df971054",
|
||||
"build/assets/ba_data/data/maps/bridgit.json": "6aea74805f4880cc11237c5734a24422",
|
||||
"build/assets/ba_data/data/maps/courtyard.json": "4b836554c8949bcd2ae382f5e3c1a9cc",
|
||||
@ -1388,10 +1388,10 @@
|
||||
"build/assets/ba_data/textures/clayStroke.ktx": "8c648180e290a4acfff1196fa358f042",
|
||||
"build/assets/ba_data/textures/clayStroke.pvr": "84c31a1a8ab4ea051a5b6a804dd952df",
|
||||
"build/assets/ba_data/textures/clayStroke_preview.png": "ec248139546f51c007148ef0250a5e0c",
|
||||
"build/assets/ba_data/textures/coin.dds": "e69e7ba8ff87d5ed9ca7c7ab96d13546",
|
||||
"build/assets/ba_data/textures/coin.ktx": "d1de4b2fd4fe028b889ed53a829f9a72",
|
||||
"build/assets/ba_data/textures/coin.pvr": "b8477ed7afdc5e460843e4d8413a2c08",
|
||||
"build/assets/ba_data/textures/coin_preview.png": "2bdae85f94cfa39eafdfc4330db90605",
|
||||
"build/assets/ba_data/textures/coin.dds": "ae86318038e6badeb5e9a7943e466c99",
|
||||
"build/assets/ba_data/textures/coin.ktx": "6202185bbf5158191b267c2c85b40dd9",
|
||||
"build/assets/ba_data/textures/coin.pvr": "d4b729057e06c2db64dd3fcae37588fb",
|
||||
"build/assets/ba_data/textures/coin_preview.png": "ee84407488f8812e08875224316f3fad",
|
||||
"build/assets/ba_data/textures/controllerIcon.dds": "9c805344b3d663d9ecf5a41d70289fc9",
|
||||
"build/assets/ba_data/textures/controllerIcon.ktx": "b5cf73a08e788f4e2a609d516715bd2b",
|
||||
"build/assets/ba_data/textures/controllerIcon.pvr": "2f9193b6eb0b7c20113d4c21b7e1ef8d",
|
||||
@ -2495,10 +2495,10 @@
|
||||
"build/assets/ba_data/textures/uiAtlas.dds": "76a861c711ea4700ad2f484adb53a837",
|
||||
"build/assets/ba_data/textures/uiAtlas.ktx": "4bd0550d4297b6b290ceceb0d3dae490",
|
||||
"build/assets/ba_data/textures/uiAtlas.pvr": "e7601e1d8cb5a03324b7e240a46eb62f",
|
||||
"build/assets/ba_data/textures/uiAtlas2.dds": "ac969ae516faf8e57800dd37801550ef",
|
||||
"build/assets/ba_data/textures/uiAtlas2.ktx": "744c37bbee308e1580e2ad569539b314",
|
||||
"build/assets/ba_data/textures/uiAtlas2.pvr": "10ee6675a5c7892efa6924bdb4ce5331",
|
||||
"build/assets/ba_data/textures/uiAtlas2_preview.png": "22077f30b690f0c21cfa03549cd55d2b",
|
||||
"build/assets/ba_data/textures/uiAtlas2.dds": "6d4b31087da911fa4fe4ccbd3935cc63",
|
||||
"build/assets/ba_data/textures/uiAtlas2.ktx": "7679ce6fab577500b956973ea10a2697",
|
||||
"build/assets/ba_data/textures/uiAtlas2.pvr": "70383679a25fa1739beb2b2b97f4fbee",
|
||||
"build/assets/ba_data/textures/uiAtlas2_preview.png": "6a48c238db2453ee0333cf554bd68054",
|
||||
"build/assets/ba_data/textures/uiAtlas_preview.png": "314c4fe9ba75ff03bb5d75d5003c2462",
|
||||
"build/assets/ba_data/textures/upButton.dds": "96f0df23bb2055a30d0073d146138a8e",
|
||||
"build/assets/ba_data/textures/upButton.ktx": "a5cc08ddb7e67a1b9e5e067d06fbbfcd",
|
||||
@ -4096,33 +4096,33 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "bf270e4b3ae3fdecff554052ab6b5b00",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "78116aab2b62c8ca18dfc534a3db829e",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "ef3f99b303627e36866d119950745815",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "d93df4793c2798d489a12d848af2daa0",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e4ac642421fc80630950dc39b0d5b488",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "51ea783b32a84a10e97275c9163dc767",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "607c744559cf66f7cc565ad6c0f21d90",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "5d869b3cd51a85de3613f39d4180196e",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d1c78f94885520e6ae8a7f3afe4d6162",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "58b78d9fbbd6c4b9515b35f9914ccd7e",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "1ee3373fb1f9a0fedc7f0f4bd574bac9",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "d3da9a35e807bc10f45f3aa38eea2a95",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "c26823caeca6398af29accbbebbb0159",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "cf58fa232755c64c71035dce8074707f",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "f077a737910c340fd42ce91e5249447e",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "37d37d17cb9878f630da859903fc8e47",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "dde17d5f07a4837ef331fe9012ed4976",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "53d938dd0541c62f5e31a871002c9291",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "2791119fd7b475228aa8cb02d6db7a96",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "bbcad92bb94abfe2dde3b568f6bb3595",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "273ffd46a618fe347a570e6bd01d54a4",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "0a166c970637de5e318e4f07e8c0aeae",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "71fee3398234820d038235f02ea7ed6a",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "682d622e82fbdf7d41f170146ae8cf6f",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "ed9a7e820ab3a59d6326b898973d5cff",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "4efa411d0d43debb7c8db1db1d9a4658",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "8892f774f2d079604d77241adaf3e529",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "c479f3ab633f0b19f3e733943b3c1c3b",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "2797e7b22388c68b2e41a1eb7c820a62",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "f58b978d2978fdf6e2f7f0cc13fbb2c7",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "1ad711461c2a65ecb1fbab1aac2aacae",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "ec90ed3ec92a6db3f8b9651f2464d8d4",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "12cc0539e86a408b01ac3b3a74cff98a",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "1f59835f71e01827f056f503302c45c4",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "c747103d9fe3206f94b54ed9ae5d4aa4",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "603f77208cb0df9161b84387631b8778",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "00a72972b6b0531b176406ad0e8d243f",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "af0063f60bb84a65ca71df83d00b9507",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "817b90e953f655e83cd8e69d1feb5526",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "c132d48c3b560ac0dcf090a3bce8ba26",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "b3c44cd6282d4100b730e997baa3f28e",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "273ffd46a618fe347a570e6bd01d54a4",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "712db7e1fcd065a3a22faddc0def8670",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "ab8467107ed371eb542e0317a7e7395d",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "4a4c19120f810ff5b4c7afbf11c23cf6",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "712db7e1fcd065a3a22faddc0def8670",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "ab8467107ed371eb542e0317a7e7395d",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "4a4c19120f810ff5b4c7afbf11c23cf6",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "bbee8acd115ca24fc14146a9fc47c676",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "8b68b56dda9a9f421823e653b752445a",
|
||||
@ -4132,14 +4132,14 @@
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "1659535e95e3047fda529543e265ac97",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "953223ec1a24ef6ba5cb7f883727af75",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "b390389ff9bb586326603b8b74f686d7",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "c8b6d94ac084539a7370c6528582cc2b",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "8e857d5edefbd2bd10837cd8224eb690",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "23d724d38988f6d41dc2c8fc818b74b1",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "b5011a047d8c23d20d1bc4405012ff1d",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "b524a2838f1d3c540afa2d63335bb036",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "e51f7a0643a02a6962c70bf884e0b8ae",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "d4aca724c3184c6c2c82e7b11c1a352a",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "f4fbab89e11f52329d65a9afcabc2e5e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "09733e1291806ece13f108ad6fb72b68",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "099e20f57cfa2c36bf7b44e389d01d9a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "aae5ce60761c700d23a480cac83a2df5",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "1fdc6ee85373af9df3a0b5eb601990af",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "809e62f1d2ac54c239a3a13c2d2c8ee7",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "68b49b66a76b9ab0d1b17de2bab19c04",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d",
|
||||
@ -4150,5 +4150,5 @@
|
||||
"src/ballistica/core/mgen/python_modules_monolithic.h": "fb967ed1c7db0c77d8deb4f00a7103c5",
|
||||
"src/ballistica/scene_v1/mgen/pyembed/binding_scene_v1.inc": "c25b263f2a31fb5ebe057db07d144879",
|
||||
"src/ballistica/template_fs/mgen/pyembed/binding_template_fs.inc": "44a45492db057bf7f7158c3b0fa11f0f",
|
||||
"src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "f5f054050d2b2fcd3763a4833fb32269"
|
||||
"src/ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc": "1081c8d6a7ed45cbe211b26b6a3b8af0"
|
||||
}
|
||||
66
CHANGELOG.md
66
CHANGELOG.md
@ -1,4 +1,41 @@
|
||||
### 1.7.37 (build 21949, api 8, 2024-07-31)
|
||||
### 1.7.37 (build 21968, api 8, 2024-08-29)
|
||||
- Playlist customization no longer requires pro.
|
||||
- Soundtrack customization no longer requires pro.
|
||||
- Switching over to the new 'toolbar mode' UI that has been in the works for
|
||||
several years. This includes a number of handy things such as consistent
|
||||
buttons and widgets for league status, currencies, inventory, and the store.
|
||||
It also adds a fixed back button on phones that should be easier to hit and a
|
||||
dock for earned treasure chests at the bottom of the screen (will finally use
|
||||
those treasure chest textures!). This is a substantial change so please holler
|
||||
if you run into anything that looks broken or doesn't behave as you think it
|
||||
should.
|
||||
- When running in 'small' UI mode (phones) the engine now uses 1300x600 as its
|
||||
virtual resolution. This gives a wider 19.5:9 aspect ratio which lines up with
|
||||
most modern smartphones, so people with such phones should no longer see
|
||||
wasted space on the sides of their screen. The virtual resolution on 'medium'
|
||||
and 'large' is now 1280x720. This gives the same 16:9 aspect ratio as the old
|
||||
resolution (1207x680) but is a cleaner number. The 16:9 aspect ratio still
|
||||
works well for tablets monitors, and TVs. When writing a UI, always be sure to
|
||||
test it on 'small', 'medium', and 'large' modes to make sure it fits on screen
|
||||
and feels similar in scale to the rest of the UI. Ideally when 'ui_v2' rolls
|
||||
around we can make it possible to build UIs that adapt better to screen sizes
|
||||
so things like fixed aspect ratios will no longer be necessary.
|
||||
- Split the main menu UI into two classes: `bauiv1.mainmenu.MainMenuWindow` and
|
||||
`bauiv1.ingamemenu.InGameMenuWindow`.
|
||||
- Removed some bits of `bauiv1` which were never fully implemented and which I
|
||||
feel were a flawed/outdated design. This includes `UILocation`,
|
||||
`UILocationWindow`, `UIEntry`, and `UIController`. The whole purpose of these
|
||||
was to add a higher level layer to the UI to make things like saving/restoring
|
||||
UI states easier, but I now plan to use `WindowState` classes to accomplish
|
||||
much of that in a more backward-compatible way. More on that below.
|
||||
- Added a new `bauiv1.Window` subclass called `bauiv1.MainWindow` which handles
|
||||
what was previously called the 'main-menu-window' system which was a bit
|
||||
ad-hoc and messy. MainMenuWindows have a built-in stack system so things like
|
||||
back-button handling are more automatic and windows don't have to hard-code
|
||||
where they came from. There are also other benefits such as better state
|
||||
saving/restoring. When writing a MainWindow, pretty much all navigation should
|
||||
only need too use methods: `can_change_main_window()`, `main_window_back()`,
|
||||
and `main_window_replace()`.
|
||||
- Finally got things updated so language testing works again, and made it a bit
|
||||
spiffier while at it. You now simply point the game at your test language and
|
||||
it will update dynamically as you make edits; no need to download any files.
|
||||
@ -11,9 +48,30 @@
|
||||
doing more heavy downloading with Asset Packages coming online so its time to
|
||||
upgrade to a more modern web client library than Python's basic built in
|
||||
urllib stuff.
|
||||
- Pasting a single line of text followed by newlines now works. Previously it
|
||||
would complain that multiple lines of text aren't supported, but now it
|
||||
just ignores the trailing newlines.
|
||||
- Pasting a single line of text followed by newlines to the dev console now
|
||||
works. Previously it would complain that multiple lines of text aren't
|
||||
supported, but now it just ignores the trailing newlines.
|
||||
- Added an 'AppModes' tab to the dev console, allowing switching between any
|
||||
AppModes defined in the current build for testing. Currently this is just
|
||||
SceneV1AppMode and EmptyAppMode. This will become more useful in the future
|
||||
when things like SquadsAppMode (Squads mode) or RemoteAppMode (the revamped
|
||||
BSRemote app) happen.
|
||||
- Added a 'UI' tab to the dev console allowing debugging virtual screen bounds
|
||||
and testing different UI scales dynamically.
|
||||
- Renamed `SceneV1AppMode` to `ClassicAppMode` and relocated it from the
|
||||
`scene_v1` featureset to the `classic` one. This makes more logical sense
|
||||
since `classic` is more about app operation and `scene_v1` is more about
|
||||
gameplay, though realistically it doesn't matter since those two featuresets
|
||||
are hopelessly entangled. Future parallels such as `squads` and `scene_v2`
|
||||
featuresets should be more independent of eachother.
|
||||
- Removed the warning when calling `ba*.screenmessage` in a game context.
|
||||
Hopefully most code has been ported at this point and it has done its job. As
|
||||
a final reminder, `ba*.screenmessage()` will only show messages locally now;
|
||||
you need to use something like `bascenev1.broadcastmessage()` to show things
|
||||
to everyone in a game.
|
||||
- Removed `efro.util.enum_by_value()` which was a workaround for a Python bug
|
||||
that has been fixed for a few versions now. Instaed of
|
||||
`enum_by_value(MyEnumType, foo)` you can simply do `MyEnumType(foo)`.
|
||||
|
||||
### 1.7.36 (build 21944, api 8, 2024-07-26)
|
||||
- Wired up Tokens, BombSquad's new purchasable currency. The first thing these
|
||||
|
||||
@ -209,8 +209,8 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/base/app_adapter/app_adapter_vr.h
|
||||
${BA_SRC_ROOT}/ballistica/base/app_mode/app_mode.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/app_mode/app_mode.h
|
||||
${BA_SRC_ROOT}/ballistica/base/app_mode/app_mode_empty.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/app_mode/app_mode_empty.h
|
||||
${BA_SRC_ROOT}/ballistica/base/app_mode/empty_app_mode.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/app_mode/empty_app_mode.h
|
||||
${BA_SRC_ROOT}/ballistica/base/assets/asset.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/assets/asset.h
|
||||
${BA_SRC_ROOT}/ballistica/base/assets/assets.cc
|
||||
@ -463,6 +463,8 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/classic/python/classic_python.h
|
||||
${BA_SRC_ROOT}/ballistica/classic/python/methods/python_methods_classic.cc
|
||||
${BA_SRC_ROOT}/ballistica/classic/python/methods/python_methods_classic.h
|
||||
${BA_SRC_ROOT}/ballistica/classic/support/classic_app_mode.cc
|
||||
${BA_SRC_ROOT}/ballistica/classic/support/classic_app_mode.h
|
||||
${BA_SRC_ROOT}/ballistica/classic/support/stress_test.cc
|
||||
${BA_SRC_ROOT}/ballistica/classic/support/stress_test.h
|
||||
${BA_SRC_ROOT}/ballistica/classic/support/v1_account.cc
|
||||
@ -657,8 +659,6 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/player_spec.h
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene.cc
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene.h
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene_v1_app_mode.cc
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene_v1_app_mode.h
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene_v1_context.cc
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene_v1_context.h
|
||||
${BA_SRC_ROOT}/ballistica/scene_v1/support/scene_v1_input_device_delegate.cc
|
||||
@ -752,8 +752,6 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/python/methods/python_methods_ui_v1.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/python/ui_v1_python.cc
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/python/ui_v1_python.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/support/root_ui.cc
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/support/root_ui.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/ui_v1.cc
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/ui_v1.h
|
||||
${BA_SRC_ROOT}/ballistica/ui_v1/widget/button_widget.cc
|
||||
|
||||
@ -201,8 +201,8 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_vr.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\app_mode_empty.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode_empty.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\empty_app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\empty_app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\assets\asset.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\assets\asset.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\assets\assets.cc" />
|
||||
@ -455,6 +455,8 @@
|
||||
<ClInclude Include="..\..\src\ballistica\classic\python\classic_python.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\python\methods\python_methods_classic.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\classic\python\methods\python_methods_classic.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\classic_app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\classic\support\classic_app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\stress_test.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\classic\support\stress_test.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\v1_account.cc" />
|
||||
@ -649,8 +651,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\player_spec.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_context.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene_v1_context.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_input_device_delegate.cc" />
|
||||
@ -744,8 +744,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\python\methods\python_methods_ui_v1.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\python\ui_v1_python.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\python\ui_v1_python.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\support\root_ui.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\support\root_ui.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\ui_v1.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\ui_v1.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\button_widget.cc" />
|
||||
|
||||
@ -37,10 +37,10 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode.h">
|
||||
<Filter>ballistica\base\app_mode</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\app_mode_empty.cc">
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\empty_app_mode.cc">
|
||||
<Filter>ballistica\base\app_mode</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode_empty.h">
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\empty_app_mode.h">
|
||||
<Filter>ballistica\base\app_mode</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\assets\asset.cc">
|
||||
@ -799,6 +799,12 @@
|
||||
<ClInclude Include="..\..\src\ballistica\classic\python\methods\python_methods_classic.h">
|
||||
<Filter>ballistica\classic\python\methods</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\classic_app_mode.cc">
|
||||
<Filter>ballistica\classic\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\classic\support\classic_app_mode.h">
|
||||
<Filter>ballistica\classic\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\stress_test.cc">
|
||||
<Filter>ballistica\classic\support</Filter>
|
||||
</ClCompile>
|
||||
@ -1381,12 +1387,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene.h">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.cc">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.h">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_context.cc">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClCompile>
|
||||
@ -1666,12 +1666,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\python\ui_v1_python.h">
|
||||
<Filter>ballistica\ui_v1\python</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\support\root_ui.cc">
|
||||
<Filter>ballistica\ui_v1\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\support\root_ui.h">
|
||||
<Filter>ballistica\ui_v1\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\ui_v1.cc">
|
||||
<Filter>ballistica\ui_v1</Filter>
|
||||
</ClCompile>
|
||||
@ -2054,7 +2048,6 @@
|
||||
<Filter Include="ballistica\ui_v1\python" />
|
||||
<Filter Include="ballistica\ui_v1\python\class" />
|
||||
<Filter Include="ballistica\ui_v1\python\methods" />
|
||||
<Filter Include="ballistica\ui_v1\support" />
|
||||
<Filter Include="ballistica\ui_v1\widget" />
|
||||
<Filter Include="external" />
|
||||
<Filter Include="external\open_dynamics_engine-ef" />
|
||||
|
||||
@ -196,8 +196,8 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_adapter\app_adapter_vr.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\app_mode_empty.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode_empty.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\empty_app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\empty_app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\assets\asset.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\assets\asset.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\assets\assets.cc" />
|
||||
@ -450,6 +450,8 @@
|
||||
<ClInclude Include="..\..\src\ballistica\classic\python\classic_python.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\python\methods\python_methods_classic.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\classic\python\methods\python_methods_classic.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\classic_app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\classic\support\classic_app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\stress_test.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\classic\support\stress_test.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\v1_account.cc" />
|
||||
@ -644,8 +646,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\player_spec.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_context.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene_v1_context.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_input_device_delegate.cc" />
|
||||
@ -739,8 +739,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\python\methods\python_methods_ui_v1.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\python\ui_v1_python.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\python\ui_v1_python.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\support\root_ui.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\support\root_ui.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\ui_v1.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\ui_v1.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\widget\button_widget.cc" />
|
||||
|
||||
@ -37,10 +37,10 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode.h">
|
||||
<Filter>ballistica\base\app_mode</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\app_mode_empty.cc">
|
||||
<ClCompile Include="..\..\src\ballistica\base\app_mode\empty_app_mode.cc">
|
||||
<Filter>ballistica\base\app_mode</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\app_mode_empty.h">
|
||||
<ClInclude Include="..\..\src\ballistica\base\app_mode\empty_app_mode.h">
|
||||
<Filter>ballistica\base\app_mode</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\assets\asset.cc">
|
||||
@ -799,6 +799,12 @@
|
||||
<ClInclude Include="..\..\src\ballistica\classic\python\methods\python_methods_classic.h">
|
||||
<Filter>ballistica\classic\python\methods</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\classic_app_mode.cc">
|
||||
<Filter>ballistica\classic\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\classic\support\classic_app_mode.h">
|
||||
<Filter>ballistica\classic\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\classic\support\stress_test.cc">
|
||||
<Filter>ballistica\classic\support</Filter>
|
||||
</ClCompile>
|
||||
@ -1381,12 +1387,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene.h">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.cc">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\scene_v1\support\scene_v1_app_mode.h">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\scene_v1\support\scene_v1_context.cc">
|
||||
<Filter>ballistica\scene_v1\support</Filter>
|
||||
</ClCompile>
|
||||
@ -1666,12 +1666,6 @@
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\python\ui_v1_python.h">
|
||||
<Filter>ballistica\ui_v1\python</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\support\root_ui.cc">
|
||||
<Filter>ballistica\ui_v1\support</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\ui_v1\support\root_ui.h">
|
||||
<Filter>ballistica\ui_v1\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\ui_v1\ui_v1.cc">
|
||||
<Filter>ballistica\ui_v1</Filter>
|
||||
</ClCompile>
|
||||
@ -2054,7 +2048,6 @@
|
||||
<Filter Include="ballistica\ui_v1\python" />
|
||||
<Filter Include="ballistica\ui_v1\python\class" />
|
||||
<Filter Include="ballistica\ui_v1\python\methods" />
|
||||
<Filter Include="ballistica\ui_v1\support" />
|
||||
<Filter Include="ballistica\ui_v1\widget" />
|
||||
<Filter Include="external" />
|
||||
<Filter Include="external\open_dynamics_engine-ef" />
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
"src/ballistica/core/platform/android/android_gl3.c"
|
||||
],
|
||||
"default_app_modes": [
|
||||
"bascenev1.SceneV1AppMode",
|
||||
"baclassic.ClassicAppMode",
|
||||
"babase.EmptyAppMode"
|
||||
],
|
||||
"efrocache_repository_url": "https://files.ballistica.net/cache/ba1",
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
cpplint==1.6.1
|
||||
dmgbuild==1.6.1
|
||||
dmgbuild==1.6.2
|
||||
filelock==3.15.4
|
||||
furo==2024.7.18
|
||||
mypy==1.11.1
|
||||
pbxproj==4.2.0
|
||||
pdoc==14.6.0
|
||||
furo==2024.8.6
|
||||
mypy==1.11.2
|
||||
pbxproj==4.2.1
|
||||
pdoc==14.6.1
|
||||
pur==7.3.2
|
||||
pylint==3.2.6
|
||||
pylsp-mypy==0.6.8
|
||||
pytest==8.3.2
|
||||
python-daemon==3.0.1
|
||||
python-lsp-black==2.0.0
|
||||
python-lsp-server==1.11.0
|
||||
python-lsp-server==1.12.0
|
||||
requests==2.32.3
|
||||
Sphinx==7.4.7
|
||||
tomlkit==0.13.0
|
||||
Sphinx==8.0.2
|
||||
tomlkit==0.13.2
|
||||
types-certifi==2021.10.8.3
|
||||
types-filelock==3.2.7
|
||||
types-requests==2.32.0.20240712
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
(project-vc-ignores . ("docs"
|
||||
"submodules"
|
||||
"src/external"
|
||||
"ballisticakit-android/BallisticaKit/src/main/cpp/src"
|
||||
"src/assets/ba_data/python-site-packages"
|
||||
"src/assets/pylib-android"
|
||||
"src/assets/pylib-apple"
|
||||
|
||||
@ -68,14 +68,14 @@
|
||||
"ba_data/python/baclassic/__pycache__/_achievement.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_ads.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_analytics.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_appdelegate.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_appmode.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_appsubsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_benchmark.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_input.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_music.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_net.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_servermode.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_store.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_subsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_tips.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/_tournament.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baclassic/__pycache__/macmusicapp.cpython-312.opt-1.pyc",
|
||||
@ -84,14 +84,14 @@
|
||||
"ba_data/python/baclassic/_achievement.py",
|
||||
"ba_data/python/baclassic/_ads.py",
|
||||
"ba_data/python/baclassic/_analytics.py",
|
||||
"ba_data/python/baclassic/_appdelegate.py",
|
||||
"ba_data/python/baclassic/_appmode.py",
|
||||
"ba_data/python/baclassic/_appsubsystem.py",
|
||||
"ba_data/python/baclassic/_benchmark.py",
|
||||
"ba_data/python/baclassic/_input.py",
|
||||
"ba_data/python/baclassic/_music.py",
|
||||
"ba_data/python/baclassic/_net.py",
|
||||
"ba_data/python/baclassic/_servermode.py",
|
||||
"ba_data/python/baclassic/_store.py",
|
||||
"ba_data/python/baclassic/_subsystem.py",
|
||||
"ba_data/python/baclassic/_tips.py",
|
||||
"ba_data/python/baclassic/_tournament.py",
|
||||
"ba_data/python/baclassic/macmusicapp.py",
|
||||
@ -123,18 +123,17 @@
|
||||
"ba_data/python/baenv.py",
|
||||
"ba_data/python/baplus/__init__.py",
|
||||
"ba_data/python/baplus/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_appsubsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_cloud.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_hooks.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baplus/__pycache__/_subsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/baplus/_appsubsystem.py",
|
||||
"ba_data/python/baplus/_cloud.py",
|
||||
"ba_data/python/baplus/_hooks.py",
|
||||
"ba_data/python/baplus/_subsystem.py",
|
||||
"ba_data/python/bascenev1/__init__.py",
|
||||
"ba_data/python/bascenev1/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_activity.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_activitytypes.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_actor.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_appmode.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_campaign.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_collision.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bascenev1/__pycache__/_coopgame.cpython-312.opt-1.pyc",
|
||||
@ -169,7 +168,6 @@
|
||||
"ba_data/python/bascenev1/_activity.py",
|
||||
"ba_data/python/bascenev1/_activitytypes.py",
|
||||
"ba_data/python/bascenev1/_actor.py",
|
||||
"ba_data/python/bascenev1/_appmode.py",
|
||||
"ba_data/python/bascenev1/_campaign.py",
|
||||
"ba_data/python/bascenev1/_collision.py",
|
||||
"ba_data/python/bascenev1/_coopgame.py",
|
||||
@ -349,42 +347,44 @@
|
||||
"ba_data/python/bascenev1lib/tutorial.py",
|
||||
"ba_data/python/batemplatefs/__init__.py",
|
||||
"ba_data/python/batemplatefs/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/batemplatefs/__pycache__/_appsubsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/batemplatefs/__pycache__/_hooks.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/batemplatefs/__pycache__/_subsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/batemplatefs/_appsubsystem.py",
|
||||
"ba_data/python/batemplatefs/_hooks.py",
|
||||
"ba_data/python/batemplatefs/_subsystem.py",
|
||||
"ba_data/python/bauiv1/__init__.py",
|
||||
"ba_data/python/bauiv1/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/__pycache__/_appsubsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/__pycache__/_hooks.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/__pycache__/_keyboard.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/__pycache__/_subsystem.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/__pycache__/_uitypes.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1/_appsubsystem.py",
|
||||
"ba_data/python/bauiv1/_hooks.py",
|
||||
"ba_data/python/bauiv1/_keyboard.py",
|
||||
"ba_data/python/bauiv1/_subsystem.py",
|
||||
"ba_data/python/bauiv1/_uitypes.py",
|
||||
"ba_data/python/bauiv1/onscreenkeyboard.py",
|
||||
"ba_data/python/bauiv1lib/__init__.py",
|
||||
"ba_data/python/bauiv1lib/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/achievements.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/appinvite.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/benchmarks.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/characterpicker.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/colorpicker.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/confirm.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/connectivity.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/continues.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/creditslist.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/debug.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/credits.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/discord.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/feedback.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/fileselector.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/getremote.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/gettickets.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/gettokens.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/helpui.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/iconpicker.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/inbox.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/ingamemenu.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/inventory.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/kiosk.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/mainmenu.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/__pycache__/party.cpython-312.opt-1.pyc",
|
||||
@ -422,6 +422,7 @@
|
||||
"ba_data/python/bauiv1lib/account/viewer.py",
|
||||
"ba_data/python/bauiv1lib/achievements.py",
|
||||
"ba_data/python/bauiv1lib/appinvite.py",
|
||||
"ba_data/python/bauiv1lib/benchmarks.py",
|
||||
"ba_data/python/bauiv1lib/characterpicker.py",
|
||||
"ba_data/python/bauiv1lib/colorpicker.py",
|
||||
"ba_data/python/bauiv1lib/config.py",
|
||||
@ -438,8 +439,7 @@
|
||||
"ba_data/python/bauiv1lib/coop/gamebutton.py",
|
||||
"ba_data/python/bauiv1lib/coop/level.py",
|
||||
"ba_data/python/bauiv1lib/coop/tournamentbutton.py",
|
||||
"ba_data/python/bauiv1lib/creditslist.py",
|
||||
"ba_data/python/bauiv1lib/debug.py",
|
||||
"ba_data/python/bauiv1lib/credits.py",
|
||||
"ba_data/python/bauiv1lib/discord.py",
|
||||
"ba_data/python/bauiv1lib/feedback.py",
|
||||
"ba_data/python/bauiv1lib/fileselector.py",
|
||||
@ -456,10 +456,12 @@
|
||||
"ba_data/python/bauiv1lib/gather/privatetab.py",
|
||||
"ba_data/python/bauiv1lib/gather/publictab.py",
|
||||
"ba_data/python/bauiv1lib/getremote.py",
|
||||
"ba_data/python/bauiv1lib/gettickets.py",
|
||||
"ba_data/python/bauiv1lib/gettokens.py",
|
||||
"ba_data/python/bauiv1lib/helpui.py",
|
||||
"ba_data/python/bauiv1lib/iconpicker.py",
|
||||
"ba_data/python/bauiv1lib/inbox.py",
|
||||
"ba_data/python/bauiv1lib/ingamemenu.py",
|
||||
"ba_data/python/bauiv1lib/inventory.py",
|
||||
"ba_data/python/bauiv1lib/keyboard/__init__.py",
|
||||
"ba_data/python/bauiv1lib/keyboard/__pycache__/__init__.cpython-312.opt-1.pyc",
|
||||
"ba_data/python/bauiv1lib/keyboard/__pycache__/englishkeyboard.cpython-312.opt-1.pyc",
|
||||
|
||||
@ -198,28 +198,27 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_achievement.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_ads.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_analytics.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_appdelegate.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_appmode.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_appsubsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_benchmark.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_input.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_music.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_net.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_servermode.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_store.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_subsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_tips.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/_tournament.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/macmusicapp.py \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/osmusic.py \
|
||||
$(BUILD_DIR)/ba_data/python/baenv.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_appsubsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_cloud.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_hooks.py \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/_subsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_activity.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_activitytypes.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_actor.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_appmode.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_campaign.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_collision.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/_coopgame.py \
|
||||
@ -325,12 +324,12 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1lib/session/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1lib/tutorial.py \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/_appsubsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/_hooks.py \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/_subsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/_appsubsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/_hooks.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/_keyboard.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/_subsystem.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/_uitypes.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/onscreenkeyboard.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__init__.py \
|
||||
@ -342,6 +341,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/account/viewer.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/achievements.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/appinvite.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/benchmarks.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/characterpicker.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/colorpicker.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/config.py \
|
||||
@ -353,8 +353,7 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/gamebutton.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/level.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/tournamentbutton.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/creditslist.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/debug.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/credits.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/discord.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/feedback.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/fileselector.py \
|
||||
@ -365,10 +364,12 @@ SCRIPT_TARGETS_PY_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/gather/privatetab.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/gather/publictab.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/getremote.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/gettickets.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/gettokens.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/helpui.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/iconpicker.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/inbox.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/ingamemenu.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/inventory.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/keyboard/__init__.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/keyboard/englishkeyboard.py \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/kiosk.py \
|
||||
@ -476,28 +477,27 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_achievement.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_ads.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_analytics.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_appdelegate.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_appmode.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_appsubsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_benchmark.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_input.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_music.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_net.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_servermode.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_store.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_subsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_tips.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/_tournament.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/macmusicapp.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baclassic/__pycache__/osmusic.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/__pycache__/baenv.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_appsubsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_cloud.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_hooks.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/baplus/__pycache__/_subsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_activity.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_activitytypes.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_actor.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_appmode.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_campaign.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_collision.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1/__pycache__/_coopgame.cpython-312.opt-1.pyc \
|
||||
@ -603,12 +603,12 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1lib/session/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bascenev1lib/__pycache__/tutorial.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_appsubsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_hooks.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/batemplatefs/__pycache__/_subsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_appsubsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_hooks.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_keyboard.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_subsystem.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/_uitypes.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1/__pycache__/onscreenkeyboard.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
@ -620,6 +620,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/account/__pycache__/viewer.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/achievements.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/appinvite.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/benchmarks.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/characterpicker.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/colorpicker.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/config.cpython-312.opt-1.pyc \
|
||||
@ -631,8 +632,7 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/gamebutton.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/level.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/coop/__pycache__/tournamentbutton.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/creditslist.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/debug.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/credits.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/discord.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/feedback.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/fileselector.cpython-312.opt-1.pyc \
|
||||
@ -643,10 +643,12 @@ SCRIPT_TARGETS_PYC_PUBLIC = \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/gather/__pycache__/privatetab.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/gather/__pycache__/publictab.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/getremote.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/gettickets.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/gettokens.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/helpui.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/iconpicker.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/inbox.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/ingamemenu.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/inventory.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/keyboard/__pycache__/__init__.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/keyboard/__pycache__/englishkeyboard.cpython-312.opt-1.pyc \
|
||||
$(BUILD_DIR)/ba_data/python/bauiv1lib/__pycache__/kiosk.cpython-312.opt-1.pyc \
|
||||
|
||||
@ -21,6 +21,7 @@ from efro.util import set_canonical_module_names
|
||||
import _babase
|
||||
from _babase import (
|
||||
add_clean_frame_callback,
|
||||
allows_ticket_sales,
|
||||
android_get_external_files_dir,
|
||||
appname,
|
||||
appnameupper,
|
||||
@ -86,6 +87,7 @@ from _babase import (
|
||||
overlay_web_browser_is_supported,
|
||||
overlay_web_browser_open_url,
|
||||
print_load_info,
|
||||
push_back_press,
|
||||
pushcall,
|
||||
quit,
|
||||
reload_media,
|
||||
@ -188,6 +190,7 @@ __all__ = [
|
||||
'AccountV2Subsystem',
|
||||
'ActivityNotFoundError',
|
||||
'ActorNotFoundError',
|
||||
'allows_ticket_sales',
|
||||
'add_clean_frame_callback',
|
||||
'android_get_external_files_dir',
|
||||
'app',
|
||||
@ -305,6 +308,7 @@ __all__ = [
|
||||
'print_error',
|
||||
'print_exception',
|
||||
'print_load_info',
|
||||
'push_back_press',
|
||||
'pushcall',
|
||||
'quit',
|
||||
'QuitType',
|
||||
|
||||
@ -36,9 +36,9 @@ if TYPE_CHECKING:
|
||||
# __FEATURESET_APP_SUBSYSTEM_IMPORTS_BEGIN__
|
||||
# This section generated by batools.appmodule; do not edit.
|
||||
|
||||
from baclassic import ClassicSubsystem
|
||||
from baplus import PlusSubsystem
|
||||
from bauiv1 import UIV1Subsystem
|
||||
from baclassic import ClassicAppSubsystem
|
||||
from baplus import PlusAppSubsystem
|
||||
from bauiv1 import UIV1AppSubsystem
|
||||
|
||||
# __FEATURESET_APP_SUBSYSTEM_IMPORTS_END__
|
||||
|
||||
@ -137,11 +137,11 @@ class App:
|
||||
|
||||
# Ask our default app modes to handle it.
|
||||
# (generated from 'default_app_modes' in projectconfig).
|
||||
import bascenev1
|
||||
import baclassic
|
||||
import babase
|
||||
|
||||
for appmode in [
|
||||
bascenev1.SceneV1AppMode,
|
||||
baclassic.ClassicAppMode,
|
||||
babase.EmptyAppMode,
|
||||
]:
|
||||
if appmode.can_handle_intent(intent):
|
||||
@ -151,6 +151,24 @@ class App:
|
||||
|
||||
# __DEFAULT_APP_MODE_SELECTION_END__
|
||||
|
||||
@override
|
||||
def testable_app_modes(self) -> list[type[AppMode]]:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
# __DEFAULT_TESTABLE_APP_MODES_BEGIN__
|
||||
# This section generated by batools.appmodule; do not edit.
|
||||
|
||||
# Return all our default_app_modes as testable.
|
||||
# (generated from 'default_app_modes' in projectconfig).
|
||||
import baclassic
|
||||
import babase
|
||||
|
||||
return [
|
||||
baclassic.ClassicAppMode,
|
||||
babase.EmptyAppMode,
|
||||
]
|
||||
# __DEFAULT_TESTABLE_APP_MODES_END__
|
||||
|
||||
def __init__(self) -> None:
|
||||
"""(internal)
|
||||
|
||||
@ -208,8 +226,9 @@ class App:
|
||||
self._config: babase.AppConfig | None = None
|
||||
self._pending_intent: AppIntent | None = None
|
||||
self._intent: AppIntent | None = None
|
||||
self._mode: AppMode | None = None
|
||||
self._mode_selector: babase.AppModeSelector | None = None
|
||||
self._mode_instances: dict[type[AppMode], AppMode] = {}
|
||||
self._mode: AppMode | None = None
|
||||
self._shutdown_task: asyncio.Task[None] | None = None
|
||||
self._shutdown_tasks: list[Coroutine[None, None, None]] = [
|
||||
self._wait_for_shutdown_suppressions(),
|
||||
@ -289,7 +308,7 @@ class App:
|
||||
"""
|
||||
assert _babase.in_logic_thread()
|
||||
|
||||
# Hold a strong reference to the task until it is done.
|
||||
# We hold a strong reference to the task until it is done.
|
||||
# Otherwise it is possible for it to be garbage collected and
|
||||
# disappear midway if the caller does not hold on to the
|
||||
# returned task, which seems like a great way to introduce
|
||||
@ -387,19 +406,19 @@ class App:
|
||||
# This section generated by batools.appmodule; do not edit.
|
||||
|
||||
@property
|
||||
def classic(self) -> ClassicSubsystem | None:
|
||||
def classic(self) -> ClassicAppSubsystem | None:
|
||||
"""Our classic subsystem (if available)."""
|
||||
return self._get_subsystem_property(
|
||||
'classic', self._create_classic_subsystem
|
||||
) # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def _create_classic_subsystem() -> ClassicSubsystem | None:
|
||||
def _create_classic_subsystem() -> ClassicAppSubsystem | None:
|
||||
# pylint: disable=cyclic-import
|
||||
try:
|
||||
from baclassic import ClassicSubsystem
|
||||
from baclassic import ClassicAppSubsystem
|
||||
|
||||
return ClassicSubsystem()
|
||||
return ClassicAppSubsystem()
|
||||
except ImportError:
|
||||
return None
|
||||
except Exception:
|
||||
@ -407,19 +426,19 @@ class App:
|
||||
return None
|
||||
|
||||
@property
|
||||
def plus(self) -> PlusSubsystem | None:
|
||||
def plus(self) -> PlusAppSubsystem | None:
|
||||
"""Our plus subsystem (if available)."""
|
||||
return self._get_subsystem_property(
|
||||
'plus', self._create_plus_subsystem
|
||||
) # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def _create_plus_subsystem() -> PlusSubsystem | None:
|
||||
def _create_plus_subsystem() -> PlusAppSubsystem | None:
|
||||
# pylint: disable=cyclic-import
|
||||
try:
|
||||
from baplus import PlusSubsystem
|
||||
from baplus import PlusAppSubsystem
|
||||
|
||||
return PlusSubsystem()
|
||||
return PlusAppSubsystem()
|
||||
except ImportError:
|
||||
return None
|
||||
except Exception:
|
||||
@ -427,19 +446,19 @@ class App:
|
||||
return None
|
||||
|
||||
@property
|
||||
def ui_v1(self) -> UIV1Subsystem:
|
||||
def ui_v1(self) -> UIV1AppSubsystem:
|
||||
"""Our ui_v1 subsystem (always available)."""
|
||||
return self._get_subsystem_property(
|
||||
'ui_v1', self._create_ui_v1_subsystem
|
||||
) # type: ignore
|
||||
|
||||
@staticmethod
|
||||
def _create_ui_v1_subsystem() -> UIV1Subsystem:
|
||||
def _create_ui_v1_subsystem() -> UIV1AppSubsystem:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
from bauiv1 import UIV1Subsystem
|
||||
from bauiv1 import UIV1AppSubsystem
|
||||
|
||||
return UIV1Subsystem()
|
||||
return UIV1AppSubsystem()
|
||||
|
||||
# __FEATURESET_APP_SUBSYSTEM_PROPERTIES_END__
|
||||
|
||||
@ -611,17 +630,32 @@ class App:
|
||||
self._update_state()
|
||||
|
||||
def _set_intent(self, intent: AppIntent) -> None:
|
||||
from babase._appmode import AppMode
|
||||
|
||||
# This should be happening in a bg thread.
|
||||
assert not _babase.in_logic_thread()
|
||||
try:
|
||||
# Ask the selector what app-mode to use for this intent.
|
||||
if self.mode_selector is None:
|
||||
raise RuntimeError('No AppModeSelector set.')
|
||||
modetype = self.mode_selector.app_mode_for_intent(intent)
|
||||
|
||||
# NOTE: Since intents are somewhat high level things, should
|
||||
# we do some universal thing like a screenmessage saying
|
||||
# 'The app cannot handle that request' on failure?
|
||||
modetype: type[AppMode] | None
|
||||
|
||||
# Special case - for testing we may force a specific
|
||||
# app-mode to handle this intent instead of going through our
|
||||
# usual selector.
|
||||
forced_mode_type = getattr(intent, '_force_app_mode_handler', None)
|
||||
if isinstance(forced_mode_type, type) and issubclass(
|
||||
forced_mode_type, AppMode
|
||||
):
|
||||
modetype = forced_mode_type
|
||||
else:
|
||||
modetype = self.mode_selector.app_mode_for_intent(intent)
|
||||
|
||||
# NOTE: Since intents are somewhat high level things,
|
||||
# perhaps we should do some universal thing like a
|
||||
# screenmessage saying 'The app cannot handle the request'
|
||||
# on failure.
|
||||
|
||||
if modetype is None:
|
||||
raise RuntimeError(
|
||||
@ -640,7 +674,9 @@ class App:
|
||||
|
||||
# Ok; seems legit. Now instantiate the mode if necessary and
|
||||
# kick back to the logic thread to apply.
|
||||
mode = modetype()
|
||||
mode = self._mode_instances.get(modetype)
|
||||
if mode is None:
|
||||
self._mode_instances[modetype] = mode = modetype()
|
||||
_babase.pushcall(
|
||||
partial(self._apply_intent, intent, mode),
|
||||
from_other_thread=True,
|
||||
@ -661,7 +697,7 @@ class App:
|
||||
return
|
||||
|
||||
# If the app-mode for this intent is different than the active
|
||||
# one, switch.
|
||||
# one, switch modes.
|
||||
if type(mode) is not type(self._mode):
|
||||
if self._mode is None:
|
||||
is_initial_mode = True
|
||||
@ -673,6 +709,18 @@ class App:
|
||||
logging.exception(
|
||||
'Error deactivating app-mode %s.', self._mode
|
||||
)
|
||||
|
||||
# Reset all subsystems. We assume subsystems won't be added
|
||||
# at this point so we can use the list directly.
|
||||
assert self._subsystem_registration_ended
|
||||
for subsystem in self._subsystems:
|
||||
try:
|
||||
subsystem.reset()
|
||||
except Exception:
|
||||
logging.exception(
|
||||
'Error in reset for subsystem %s.', subsystem
|
||||
)
|
||||
|
||||
self._mode = mode
|
||||
try:
|
||||
mode.on_activate()
|
||||
@ -750,8 +798,8 @@ class App:
|
||||
self.meta.start_scan(scan_complete_cb=self._on_meta_scan_complete)
|
||||
|
||||
# Inform all app subsystems in the same order they were inited.
|
||||
# Operate on a copy here because subsystems can still be added
|
||||
# at this point.
|
||||
# Operate on a copy of the list here because subsystems can
|
||||
# still be added at this point.
|
||||
for subsystem in self._subsystems.copy():
|
||||
try:
|
||||
subsystem.on_app_loading()
|
||||
|
||||
@ -31,7 +31,7 @@ class AppMode:
|
||||
AppExperience associated with the AppMode must be supported by
|
||||
the current app and runtime environment.
|
||||
"""
|
||||
# FIXME: check AppExperience.
|
||||
# TODO: check AppExperience.
|
||||
return cls._supports_intent(intent)
|
||||
|
||||
@classmethod
|
||||
|
||||
@ -11,7 +11,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class AppModeSelector:
|
||||
"""Defines which AppModes to use to handle given AppIntents.
|
||||
"""Defines which AppModes are available or used to handle given AppIntents.
|
||||
|
||||
Category: **App Classes**
|
||||
|
||||
@ -29,4 +29,16 @@ class AppModeSelector:
|
||||
This may be called in a background thread, so avoid any calls
|
||||
limited to logic thread use/etc.
|
||||
"""
|
||||
raise NotImplementedError('app_mode_for_intent() should be overridden.')
|
||||
raise NotImplementedError()
|
||||
|
||||
def testable_app_modes(self) -> list[type[AppMode]]:
|
||||
"""Return a list of modes to appear in the dev-console app-mode ui.
|
||||
|
||||
The user can switch between these app modes for testing. App-modes
|
||||
will be passed an AppIntentDefault when selected by the user.
|
||||
|
||||
Note that in normal circumstances AppModes should never be
|
||||
selected explicitly by the user but rather determined implicitly
|
||||
based on AppIntents.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
@ -53,3 +53,10 @@ class AppSubsystem:
|
||||
|
||||
def do_apply_app_config(self) -> None:
|
||||
"""Called when the app config should be applied."""
|
||||
|
||||
def reset(self) -> None:
|
||||
"""Reset the subsystem to a default state.
|
||||
|
||||
This is called when switching app modes, but may be called
|
||||
at other times too.
|
||||
"""
|
||||
|
||||
@ -13,6 +13,8 @@ import _babase
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any, Literal
|
||||
|
||||
from babase import AppMode
|
||||
|
||||
|
||||
class DevConsoleTab:
|
||||
"""Defines behavior for a tab in the dev-console."""
|
||||
@ -101,6 +103,102 @@ class DevConsoleTabPython(DevConsoleTab):
|
||||
self.python_terminal()
|
||||
|
||||
|
||||
class DevConsoleTabAppModes(DevConsoleTab):
|
||||
"""Tab to switch app modes."""
|
||||
|
||||
@override
|
||||
def refresh(self) -> None:
|
||||
from functools import partial
|
||||
|
||||
modes = _babase.app.mode_selector.testable_app_modes()
|
||||
self.text(
|
||||
'Available AppModes:',
|
||||
scale=0.8,
|
||||
pos=(15, 55),
|
||||
h_anchor='left',
|
||||
h_align='left',
|
||||
v_align='none',
|
||||
)
|
||||
for i, mode in enumerate(modes):
|
||||
self.button(
|
||||
f'{mode.__module__}.{mode.__qualname__}',
|
||||
pos=(10 + i * 260, 10),
|
||||
size=(250, 40),
|
||||
h_anchor='left',
|
||||
label_scale=0.6,
|
||||
call=partial(self._set_app_mode, mode),
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _set_app_mode(mode: type[AppMode]) -> None:
|
||||
from babase._appintent import AppIntentDefault
|
||||
|
||||
intent = AppIntentDefault()
|
||||
|
||||
# Use private functionality to force a specific app-mode to
|
||||
# handle this intent. Note that this should never be done
|
||||
# outside of this explicit testing case. It is the app's job to
|
||||
# determine which app-mode should be used to handle a given
|
||||
# intent.
|
||||
setattr(intent, '_force_app_mode_handler', mode)
|
||||
|
||||
_babase.app.set_intent(intent)
|
||||
|
||||
|
||||
class DevConsoleTabUI(DevConsoleTab):
|
||||
"""Tab to debug/test UI stuff."""
|
||||
|
||||
@override
|
||||
def refresh(self) -> None:
|
||||
|
||||
self.text(
|
||||
'UI Testing: Make sure all static UI fits in the'
|
||||
' virtual screen at all UI scales (not counting things'
|
||||
' that follow screen edges).',
|
||||
scale=0.8,
|
||||
pos=(15, 55),
|
||||
h_anchor='left',
|
||||
h_align='left',
|
||||
v_align='none',
|
||||
)
|
||||
|
||||
ui_overlay = _babase.get_draw_ui_bounds()
|
||||
self.button(
|
||||
'Hide Virtual Screen' if ui_overlay else 'Show Virtual Screen',
|
||||
pos=(10, 10),
|
||||
size=(200, 30),
|
||||
h_anchor='left',
|
||||
label_scale=0.6,
|
||||
call=self.toggle_ui_overlay,
|
||||
)
|
||||
x = 320
|
||||
self.text(
|
||||
'UI Scale:',
|
||||
pos=(x - 10, 15),
|
||||
h_anchor='left',
|
||||
h_align='right',
|
||||
v_align='none',
|
||||
scale=0.6,
|
||||
)
|
||||
|
||||
bwidth = 100
|
||||
for sz in ('small', 'medium', 'large'):
|
||||
self.button(
|
||||
sz,
|
||||
pos=(x, 10),
|
||||
size=(bwidth, 30),
|
||||
h_anchor='left',
|
||||
label_scale=0.6,
|
||||
call=lambda: _babase.screenmessage('UNDER CONSTRUCTION.'),
|
||||
)
|
||||
x += bwidth + 10
|
||||
|
||||
def toggle_ui_overlay(self) -> None:
|
||||
"""Toggle UI overlay drawing."""
|
||||
_babase.set_draw_ui_bounds(not _babase.get_draw_ui_bounds())
|
||||
self.request_refresh()
|
||||
|
||||
|
||||
class DevConsoleTabTest(DevConsoleTab):
|
||||
"""Test dev-console tab."""
|
||||
|
||||
@ -157,7 +255,9 @@ class DevConsoleSubsystem:
|
||||
# All tabs in the dev-console. Add your own stuff here via
|
||||
# plugins or whatnot.
|
||||
self.tabs: list[DevConsoleTabEntry] = [
|
||||
DevConsoleTabEntry('Python', DevConsoleTabPython)
|
||||
DevConsoleTabEntry('Python', DevConsoleTabPython),
|
||||
DevConsoleTabEntry('AppModes', DevConsoleTabAppModes),
|
||||
DevConsoleTabEntry('UI', DevConsoleTabUI),
|
||||
]
|
||||
if os.environ.get('BA_DEV_CONSOLE_TEST_TAB', '0') == '1':
|
||||
self.tabs.append(DevConsoleTabEntry('Test', DevConsoleTabTest))
|
||||
|
||||
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class EmptyAppMode(AppMode):
|
||||
"""An empty app mode that can be used as a fallback/etc."""
|
||||
"""An AppMode that does not do much at all."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
@ -32,17 +32,17 @@ class EmptyAppMode(AppMode):
|
||||
@override
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
if isinstance(intent, AppIntentExec):
|
||||
_babase.empty_app_mode_handle_intent_exec(intent.code)
|
||||
_babase.empty_app_mode_handle_app_intent_exec(intent.code)
|
||||
return
|
||||
assert isinstance(intent, AppIntentDefault)
|
||||
_babase.empty_app_mode_handle_intent_default()
|
||||
_babase.empty_app_mode_handle_app_intent_default()
|
||||
|
||||
@override
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.on_empty_app_mode_activate()
|
||||
_babase.empty_app_mode_activate()
|
||||
|
||||
@override
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_babase.on_empty_app_mode_deactivate()
|
||||
_babase.empty_app_mode_deactivate()
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Classic ballistica components.
|
||||
"""Components for the classic BombSquad experience.
|
||||
|
||||
This package is used as a 'dumping ground' for functionality that is
|
||||
necessary to keep legacy parts of the app working, but which may no
|
||||
longer be the best way to do things going forward.
|
||||
This package is used as a dumping ground for functionality that is
|
||||
necessary to keep classic BombSquad working, but which may no longer be
|
||||
the best way to do things going forward.
|
||||
|
||||
New code should try to avoid using code from here when possible.
|
||||
|
||||
Functionality in this package should be exposed through the
|
||||
ClassicSubsystem. This allows type-checked code to go through the
|
||||
ClassicAppSubsystem. This allows type-checked code to go through the
|
||||
babase.app.classic singleton which forces it to explicitly handle the
|
||||
possibility of babase.app.classic being None. When code instead imports
|
||||
classic submodules directly, it is much harder to make it cleanly handle
|
||||
@ -19,20 +19,28 @@ classic not being present.
|
||||
# ba_meta require api 8
|
||||
|
||||
# Note: Code relying on classic should import things from here *only*
|
||||
# for type-checking and use the versions in app.classic at runtime; that
|
||||
# way type-checking will cleanly cover the classic-not-present case
|
||||
# (app.classic being None).
|
||||
# for type-checking and use the versions in ba*.app.classic at runtime;
|
||||
# that way type-checking will cleanly cover the classic-not-present case
|
||||
# (ba*.app.classic being None).
|
||||
import logging
|
||||
|
||||
from baclassic._subsystem import ClassicSubsystem
|
||||
from efro.util import set_canonical_module_names
|
||||
|
||||
from baclassic._appmode import ClassicAppMode
|
||||
from baclassic._appsubsystem import ClassicAppSubsystem
|
||||
from baclassic._achievement import Achievement, AchievementSubsystem
|
||||
|
||||
__all__ = [
|
||||
'ClassicSubsystem',
|
||||
'ClassicAppMode',
|
||||
'ClassicAppSubsystem',
|
||||
'Achievement',
|
||||
'AchievementSubsystem',
|
||||
]
|
||||
|
||||
# We want stuff here to show up as packagename.Foo instead of
|
||||
# packagename._submodule.Foo.
|
||||
set_canonical_module_names(globals())
|
||||
|
||||
# Sanity check: we want to keep ballistica's dependencies and
|
||||
# bootstrapping order clearly defined; let's check a few particular
|
||||
# modules to make sure they never directly or indirectly import us
|
||||
|
||||
@ -1,46 +0,0 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Defines AppDelegate class for handling high level app functionality."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
import babase
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable
|
||||
import bascenev1
|
||||
|
||||
|
||||
class AppDelegate:
|
||||
"""Defines handlers for high level app functionality.
|
||||
|
||||
Category: App Classes
|
||||
"""
|
||||
|
||||
def create_default_game_settings_ui(
|
||||
self,
|
||||
gameclass: type[bascenev1.GameActivity],
|
||||
sessiontype: type[bascenev1.Session],
|
||||
settings: dict | None,
|
||||
completion_call: Callable[[dict | None], None],
|
||||
) -> None:
|
||||
"""Launch a UI to configure the given game config.
|
||||
|
||||
It should manipulate the contents of config and call completion_call
|
||||
when done.
|
||||
"""
|
||||
# Replace the main window once we come up successfully.
|
||||
from bauiv1lib.playlist.editgame import PlaylistEditGameWindow
|
||||
|
||||
assert babase.app.classic is not None
|
||||
babase.app.ui_v1.clear_main_menu_window(transition='out_left')
|
||||
babase.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditGameWindow(
|
||||
gameclass,
|
||||
sessiontype,
|
||||
settings,
|
||||
completion_call=completion_call,
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check since we don't know.
|
||||
)
|
||||
310
src/assets/ba_data/python/baclassic/_appmode.py
Normal file
310
src/assets/ba_data/python/baclassic/_appmode.py
Normal file
@ -0,0 +1,310 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Contains ClassicAppMode."""
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from functools import partial
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from bacommon.app import AppExperience
|
||||
from babase import (
|
||||
app,
|
||||
AppMode,
|
||||
AppIntentExec,
|
||||
AppIntentDefault,
|
||||
invoke_main_menu,
|
||||
screenmessage,
|
||||
)
|
||||
|
||||
import _baclassic
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from babase import AppIntent
|
||||
from bauiv1 import UIV1AppSubsystem, MainWindow
|
||||
|
||||
|
||||
class ClassicAppMode(AppMode):
|
||||
"""AppMode for the classic BombSquad experience."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.MELEE
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
@override
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
if isinstance(intent, AppIntentExec):
|
||||
_baclassic.classic_app_mode_handle_app_intent_exec(intent.code)
|
||||
return
|
||||
assert isinstance(intent, AppIntentDefault)
|
||||
_baclassic.classic_app_mode_handle_app_intent_default()
|
||||
|
||||
@override
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_baclassic.classic_app_mode_activate()
|
||||
|
||||
# Wire up the root ui to do what we want.
|
||||
ui = app.ui_v1
|
||||
ui.root_ui_calls[ui.RootUIElement.ACCOUNT_BUTTON] = (
|
||||
self._root_ui_account_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.MENU_BUTTON] = (
|
||||
self._root_ui_menu_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.SQUAD_BUTTON] = (
|
||||
self._root_ui_squad_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.SETTINGS_BUTTON] = (
|
||||
self._root_ui_settings_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.STORE_BUTTON] = (
|
||||
self._root_ui_store_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.INVENTORY_BUTTON] = (
|
||||
self._root_ui_inventory_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.GET_TOKENS_BUTTON] = (
|
||||
self._root_ui_get_tokens_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.INBOX_BUTTON] = (
|
||||
self._root_ui_inbox_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.TICKETS_METER] = (
|
||||
self._root_ui_tickets_meter_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.TOKENS_METER] = (
|
||||
self._root_ui_tokens_meter_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.TROPHY_METER] = (
|
||||
self._root_ui_trophy_meter_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.LEVEL_METER] = (
|
||||
self._root_ui_level_meter_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.ACHIEVEMENTS_BUTTON] = (
|
||||
self._root_ui_achievements_press
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_1] = partial(
|
||||
self._root_ui_chest_slot_pressed, 1
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_2] = partial(
|
||||
self._root_ui_chest_slot_pressed, 2
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_3] = partial(
|
||||
self._root_ui_chest_slot_pressed, 3
|
||||
)
|
||||
ui.root_ui_calls[ui.RootUIElement.CHEST_SLOT_4] = partial(
|
||||
self._root_ui_chest_slot_pressed, 4
|
||||
)
|
||||
|
||||
@override
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_baclassic.classic_app_mode_deactivate()
|
||||
|
||||
@override
|
||||
def on_app_active_changed(self) -> None:
|
||||
# If we've gone inactive, bring up the main menu, which has the
|
||||
# side effect of pausing the action (when possible).
|
||||
if not app.active:
|
||||
invoke_main_menu()
|
||||
|
||||
def _jump_to_main_window(self, window: MainWindow) -> None:
|
||||
"""Jump to a window with the main menu as its parent."""
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
old_window = ui.get_main_window()
|
||||
if isinstance(old_window, MainMenuWindow):
|
||||
old_window.main_window_replace(window)
|
||||
else:
|
||||
# Blow away the window stack.
|
||||
ui.clear_main_window()
|
||||
|
||||
ui.set_main_window(
|
||||
window,
|
||||
from_window=False, # Disable from-check.
|
||||
back_state=MainMenuWindow.do_get_main_window_state(),
|
||||
)
|
||||
|
||||
def _root_ui_menu_press(self) -> None:
|
||||
from babase import push_back_press
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
# If *any* main-window is up, kill it.
|
||||
old_window = ui.get_main_window()
|
||||
if old_window is not None:
|
||||
ui.clear_main_window()
|
||||
return
|
||||
|
||||
push_back_press()
|
||||
|
||||
def _root_ui_account_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.account.settings import AccountSettingsWindow
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
# If the window is already showing, back out of it.
|
||||
current_main_window = ui.get_main_window()
|
||||
if isinstance(current_main_window, AccountSettingsWindow):
|
||||
current_main_window.main_window_back()
|
||||
return
|
||||
|
||||
self._jump_to_main_window(
|
||||
AccountSettingsWindow(
|
||||
origin_widget=bauiv1.get_special_widget('account_button')
|
||||
)
|
||||
)
|
||||
|
||||
def _root_ui_squad_press(self) -> None:
|
||||
import bauiv1
|
||||
|
||||
btn = bauiv1.get_special_widget('squad_button')
|
||||
center = btn.get_screen_space_center()
|
||||
if bauiv1.app.classic is not None:
|
||||
bauiv1.app.classic.party_icon_activate(center)
|
||||
else:
|
||||
logging.warning('party_icon_activate: no classic.')
|
||||
|
||||
def _root_ui_settings_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.settings.allsettings import AllSettingsWindow
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
# If the window is already showing, back out of it.
|
||||
current_main_window = ui.get_main_window()
|
||||
if isinstance(current_main_window, AllSettingsWindow):
|
||||
current_main_window.main_window_back()
|
||||
return
|
||||
|
||||
self._jump_to_main_window(
|
||||
AllSettingsWindow(
|
||||
origin_widget=bauiv1.get_special_widget('settings_button')
|
||||
)
|
||||
)
|
||||
|
||||
def _root_ui_achievements_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.achievements import AchievementsWindow
|
||||
|
||||
btn = bauiv1.get_special_widget('achievements_button')
|
||||
|
||||
AchievementsWindow(position=btn.get_screen_space_center())
|
||||
|
||||
def _root_ui_inbox_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.inbox import InboxWindow
|
||||
|
||||
btn = bauiv1.get_special_widget('inbox_button')
|
||||
|
||||
InboxWindow(position=btn.get_screen_space_center())
|
||||
|
||||
def _root_ui_store_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.store.browser import StoreBrowserWindow
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
# If the window is already showing, back out of it.
|
||||
current_main_window = ui.get_main_window()
|
||||
if isinstance(current_main_window, StoreBrowserWindow):
|
||||
current_main_window.main_window_back()
|
||||
return
|
||||
|
||||
self._jump_to_main_window(
|
||||
StoreBrowserWindow(
|
||||
origin_widget=bauiv1.get_special_widget('store_button')
|
||||
)
|
||||
)
|
||||
|
||||
def _root_ui_tickets_meter_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow
|
||||
|
||||
ResourceTypeInfoWindow(
|
||||
'tickets', origin_widget=bauiv1.get_special_widget('tickets_meter')
|
||||
)
|
||||
|
||||
def _root_ui_tokens_meter_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow
|
||||
|
||||
ResourceTypeInfoWindow(
|
||||
'tokens', origin_widget=bauiv1.get_special_widget('tokens_meter')
|
||||
)
|
||||
|
||||
def _root_ui_trophy_meter_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.account import show_sign_in_prompt
|
||||
from bauiv1lib.league.rankwindow import LeagueRankWindow
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
# If the window is already showing, back out of it.
|
||||
current_main_window = ui.get_main_window()
|
||||
if isinstance(current_main_window, LeagueRankWindow):
|
||||
current_main_window.main_window_back()
|
||||
return
|
||||
|
||||
plus = bauiv1.app.plus
|
||||
assert plus is not None
|
||||
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
|
||||
self._jump_to_main_window(
|
||||
LeagueRankWindow(
|
||||
origin_widget=bauiv1.get_special_widget('trophy_meter')
|
||||
)
|
||||
)
|
||||
|
||||
def _root_ui_level_meter_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow
|
||||
|
||||
ResourceTypeInfoWindow(
|
||||
'xp', origin_widget=bauiv1.get_special_widget('level_meter')
|
||||
)
|
||||
|
||||
def _root_ui_inventory_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.inventory import InventoryWindow
|
||||
|
||||
ui = app.ui_v1
|
||||
|
||||
# If the window is already showing, back out of it.
|
||||
current_main_window = ui.get_main_window()
|
||||
if isinstance(current_main_window, InventoryWindow):
|
||||
current_main_window.main_window_back()
|
||||
return
|
||||
|
||||
self._jump_to_main_window(
|
||||
InventoryWindow(
|
||||
origin_widget=bauiv1.get_special_widget('inventory_button')
|
||||
)
|
||||
)
|
||||
|
||||
def _root_ui_get_tokens_press(self) -> None:
|
||||
import bauiv1
|
||||
from bauiv1lib.gettokens import GetTokensWindow
|
||||
|
||||
GetTokensWindow(
|
||||
origin_widget=bauiv1.get_special_widget('get_tokens_button')
|
||||
)
|
||||
|
||||
def _root_ui_chest_slot_pressed(self, index: int) -> None:
|
||||
print(f'CHEST {index} PRESSED')
|
||||
screenmessage('UNDER CONSTRUCTION.')
|
||||
@ -29,12 +29,11 @@ if TYPE_CHECKING:
|
||||
from bascenev1lib.actor import spazappearance
|
||||
from bauiv1lib.party import PartyWindow
|
||||
|
||||
from baclassic._appdelegate import AppDelegate
|
||||
from baclassic._servermode import ServerController
|
||||
from baclassic._net import MasterServerCallback
|
||||
|
||||
|
||||
class ClassicSubsystem(babase.AppSubsystem):
|
||||
class ClassicAppSubsystem(babase.AppSubsystem):
|
||||
"""Subsystem for classic functionality in the app.
|
||||
|
||||
The single shared instance of this app can be accessed at
|
||||
@ -111,8 +110,12 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
self.did_menu_intro = False # FIXME: Move to mainmenu class.
|
||||
self.main_menu_window_refresh_check_count = 0 # FIXME: Mv to mainmenu.
|
||||
self.invite_confirm_windows: list[Any] = [] # FIXME: Don't use Any.
|
||||
self.delegate: AppDelegate | None = None
|
||||
self.party_window: weakref.ref[PartyWindow] | None = None
|
||||
self.main_menu_resume_callbacks: list = []
|
||||
# Switch our overall game selection UI flow between Play and
|
||||
# Private-party playlist selection modes; should do this in
|
||||
# a more elegant way once we revamp high level UI stuff a bit.
|
||||
self.selecting_private_party_playlist: bool = False
|
||||
|
||||
# Store.
|
||||
self.store_layout: dict[str, list[dict[str, Any]]] | None = None
|
||||
@ -120,6 +123,16 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
self.pro_sale_start_time: int | None = None
|
||||
self.pro_sale_start_val: int | None = None
|
||||
|
||||
def add_main_menu_close_callback(self, call: Callable[[], Any]) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
# If there's no main window up, just call immediately.
|
||||
if not babase.app.ui_v1.has_main_window():
|
||||
with babase.ContextRef.empty():
|
||||
call()
|
||||
else:
|
||||
self.main_menu_resume_callbacks.append(call)
|
||||
|
||||
@property
|
||||
def platform(self) -> str:
|
||||
"""Name of the current platform.
|
||||
@ -154,8 +167,6 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
from bascenev1lib.actor import spazappearance
|
||||
from bascenev1lib import maps as stdmaps
|
||||
|
||||
from baclassic._appdelegate import AppDelegate
|
||||
|
||||
plus = babase.app.plus
|
||||
assert plus is not None
|
||||
|
||||
@ -164,8 +175,6 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
|
||||
self.music.on_app_loading()
|
||||
|
||||
self.delegate = AppDelegate()
|
||||
|
||||
# Non-test, non-debug builds should generally be blessed; warn if not.
|
||||
# (so I don't accidentally release a build that can't play tourneys)
|
||||
if not env.debug and not env.test and not plus.is_blessed():
|
||||
@ -374,7 +383,7 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
assert plus is not None
|
||||
|
||||
if reset_ui:
|
||||
babase.app.ui_v1.clear_main_menu_window()
|
||||
babase.app.ui_v1.clear_main_window()
|
||||
|
||||
if isinstance(bascenev1.get_foreground_host_session(), MainMenuSession):
|
||||
# It may be possible we're on the main menu but the screen is faded
|
||||
@ -684,13 +693,13 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
babase.Call(ServerDialogWindow, sddata),
|
||||
)
|
||||
|
||||
def ticket_icon_press(self) -> None:
|
||||
"""(internal)"""
|
||||
from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow
|
||||
# def root_ui_ticket_icon_press(self) -> None:
|
||||
# """(internal)"""
|
||||
# from bauiv1lib.resourcetypeinfo import ResourceTypeInfoWindow
|
||||
|
||||
ResourceTypeInfoWindow(
|
||||
origin_widget=bauiv1.get_special_widget('tickets_info_button')
|
||||
)
|
||||
# ResourceTypeInfoWindow(
|
||||
# origin_widget=bauiv1.get_special_widget('tickets_meter')
|
||||
# )
|
||||
|
||||
def show_url_window(self, address: str) -> None:
|
||||
"""(internal)"""
|
||||
@ -781,6 +790,9 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
|
||||
assert app.env.gui
|
||||
|
||||
# Play explicit swish sound so it occurs due to keypresses/etc.
|
||||
# This means we have to disable it for any button or else we get
|
||||
# double.
|
||||
bauiv1.getsound('swish').play()
|
||||
|
||||
# If it exists, dismiss it; otherwise make a new one.
|
||||
@ -794,18 +806,132 @@ class ClassicSubsystem(babase.AppSubsystem):
|
||||
|
||||
def device_menu_press(self, device_id: int | None) -> None:
|
||||
"""(internal)"""
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
from bauiv1lib.ingamemenu import InGameMenuWindow
|
||||
from bauiv1 import set_ui_input_device
|
||||
|
||||
assert babase.app is not None
|
||||
in_main_menu = babase.app.ui_v1.has_main_menu_window()
|
||||
in_main_menu = babase.app.ui_v1.has_main_window()
|
||||
if not in_main_menu:
|
||||
set_ui_input_device(device_id)
|
||||
|
||||
# Hack(ish). We play swish sound here so it happens for
|
||||
# device presses, but this means we need to disable default
|
||||
# swish sounds for any menu buttons or we'll get double.
|
||||
if babase.app.env.gui:
|
||||
bauiv1.getsound('swish').play()
|
||||
|
||||
babase.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow().get_root_widget(),
|
||||
babase.app.ui_v1.set_main_window(
|
||||
InGameMenuWindow(),
|
||||
from_window=False, # Disable check here.
|
||||
is_top_level=True,
|
||||
)
|
||||
|
||||
def invoke_main_menu_ui(self) -> None:
|
||||
"""Bring up main menu ui."""
|
||||
# Bring up the last place we were, or start at the main menu otherwise.
|
||||
app = bauiv1.app
|
||||
env = app.env
|
||||
with bascenev1.ContextRef.empty():
|
||||
from bauiv1lib import specialoffer
|
||||
|
||||
assert app.classic is not None
|
||||
if app.env.headless:
|
||||
# UI stuff fails now in headless builds; avoid it.
|
||||
pass
|
||||
else:
|
||||
# main_menu_location = (
|
||||
# bascenev1.app.ui_v1.get_main_menu_location()
|
||||
# )
|
||||
|
||||
# When coming back from a kiosk-mode game, jump to
|
||||
# the kiosk start screen.
|
||||
if env.demo or env.arcade:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.kiosk import KioskWindow
|
||||
|
||||
app.ui_v1.set_main_window(
|
||||
KioskWindow(), from_window=False # Disable check here.
|
||||
)
|
||||
# ..or in normal cases go back to the main menu
|
||||
else:
|
||||
# if main_menu_location == 'Gather':
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.gather import GatherWindow
|
||||
|
||||
# app.ui_v1.set_main_window(
|
||||
# GatherWindow(transition=None),
|
||||
# from_window=False, # Disable check here.
|
||||
# )
|
||||
# elif main_menu_location == 'Watch':
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.watch import WatchWindow
|
||||
|
||||
# app.ui_v1.set_main_window(
|
||||
# WatchWindow(transition=None),
|
||||
# from_window=False, # Disable check here.
|
||||
# )
|
||||
# elif main_menu_location == 'Team Game Select':
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.playlist.browser import (
|
||||
# PlaylistBrowserWindow,
|
||||
# )
|
||||
|
||||
# app.ui_v1.set_main_window(
|
||||
# PlaylistBrowserWindow(
|
||||
# sessiontype=bascenev1.DualTeamSession,
|
||||
# transition=None,
|
||||
# ),
|
||||
# from_window=False, # Disable check here.
|
||||
# )
|
||||
# elif main_menu_location == 'Free-for-All Game Select':
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.playlist.browser import (
|
||||
# PlaylistBrowserWindow,
|
||||
# )
|
||||
|
||||
# app.ui_v1.set_main_window(
|
||||
# PlaylistBrowserWindow(
|
||||
# sessiontype=bascenev1.FreeForAllSession,
|
||||
# transition=None,
|
||||
# ),
|
||||
# from_window=False, # Disable check here.
|
||||
# )
|
||||
# elif main_menu_location == 'Coop Select':
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
# app.ui_v1.set_main_window(
|
||||
# CoopBrowserWindow(transition=None),
|
||||
# from_window=False, # Disable check here.
|
||||
# )
|
||||
# elif main_menu_location == 'Benchmarks & Stress Tests':
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.debug import DebugWindow
|
||||
|
||||
# app.ui_v1.set_main_window(
|
||||
# DebugWindow(transition=None),
|
||||
# from_window=False, # Disable check here.
|
||||
# )
|
||||
# else:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
app.ui_v1.set_main_window(
|
||||
MainMenuWindow(transition=None),
|
||||
from_window=False, # Disable check.
|
||||
is_top_level=True,
|
||||
)
|
||||
|
||||
# attempt to show any pending offers immediately.
|
||||
# If that doesn't work, try again in a few seconds
|
||||
# (we may not have heard back from the server)
|
||||
# ..if that doesn't work they'll just have to wait
|
||||
# until the next opportunity.
|
||||
if not specialoffer.show_offer():
|
||||
|
||||
def try_again() -> None:
|
||||
if not specialoffer.show_offer():
|
||||
# Try one last time..
|
||||
bauiv1.apptimer(2.0, specialoffer.show_offer)
|
||||
|
||||
bauiv1.apptimer(2.0, try_again)
|
||||
@ -16,6 +16,8 @@ from bascenev1 import MusicType
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
||||
import bauiv1
|
||||
|
||||
|
||||
class MusicPlayMode(Enum):
|
||||
"""Influences behavior when playing music.
|
||||
@ -389,7 +391,7 @@ class MusicPlayer:
|
||||
callback: Callable[[Any], None],
|
||||
current_entry: Any,
|
||||
selection_target_name: str,
|
||||
) -> Any:
|
||||
) -> bauiv1.MainWindow:
|
||||
"""Summons a UI to select a new soundtrack entry."""
|
||||
return self.on_select_entry(
|
||||
callback, current_entry, selection_target_name
|
||||
@ -432,11 +434,12 @@ class MusicPlayer:
|
||||
callback: Callable[[Any], None],
|
||||
current_entry: Any,
|
||||
selection_target_name: str,
|
||||
) -> Any:
|
||||
) -> bauiv1.MainWindow:
|
||||
"""Present a GUI to select an entry.
|
||||
|
||||
The callback should be called with a valid entry or None to
|
||||
signify that the default soundtrack should be used.."""
|
||||
raise NotImplementedError()
|
||||
|
||||
# Subclasses should override the following:
|
||||
|
||||
|
||||
@ -15,6 +15,8 @@ from baclassic._music import MusicPlayer
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
||||
import bauiv1
|
||||
|
||||
|
||||
class MacMusicAppMusicPlayer(MusicPlayer):
|
||||
"""A music-player that utilizes the macOS Music.app for playback.
|
||||
@ -33,7 +35,7 @@ class MacMusicAppMusicPlayer(MusicPlayer):
|
||||
callback: Callable[[Any], None],
|
||||
current_entry: Any,
|
||||
selection_target_name: str,
|
||||
) -> Any:
|
||||
) -> bauiv1.MainWindow:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.soundtrack import entrytypeselect as etsel
|
||||
|
||||
|
||||
@ -16,6 +16,8 @@ from baclassic._music import MusicPlayer
|
||||
if TYPE_CHECKING:
|
||||
from typing import Callable, Any
|
||||
|
||||
import bauiv1
|
||||
|
||||
|
||||
class OSMusicPlayer(MusicPlayer):
|
||||
"""Music player that talks to internal C++ layer for functionality.
|
||||
@ -39,7 +41,7 @@ class OSMusicPlayer(MusicPlayer):
|
||||
callback: Callable[[Any], None],
|
||||
current_entry: Any,
|
||||
selection_target_name: str,
|
||||
) -> Any:
|
||||
) -> bauiv1.MainWindow:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.soundtrack.entrytypeselect import (
|
||||
SoundtrackEntryTypeSelectWindow,
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21949
|
||||
TARGET_BALLISTICA_BUILD = 21968
|
||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||
|
||||
|
||||
|
||||
@ -5,23 +5,23 @@
|
||||
This code concerns sensitive things like accounts and master-server
|
||||
communication so the native C++ parts of it remain closed. Native
|
||||
precompiled static libraries of this portion are provided for those who
|
||||
want to compile the rest of the engine, and a fully open-source engine
|
||||
can also be built by removing this 'plus' feature-set.
|
||||
want to compile the rest of the engine, or a fully open-source app
|
||||
can also be built by removing this feature-set.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
# Note: there's not much here.
|
||||
# All comms with this feature-set should go through app.plus.
|
||||
# Note: there's not much here. Most interaction with this feature-set
|
||||
# should go through ba*.app.plus.
|
||||
|
||||
import logging
|
||||
|
||||
from baplus._cloud import CloudSubsystem
|
||||
from baplus._subsystem import PlusSubsystem
|
||||
from baplus._appsubsystem import PlusAppSubsystem
|
||||
|
||||
__all__ = [
|
||||
'CloudSubsystem',
|
||||
'PlusSubsystem',
|
||||
'PlusAppSubsystem',
|
||||
]
|
||||
|
||||
# Sanity check: we want to keep ballistica's dependencies and
|
||||
|
||||
@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
||||
from baplus._cloud import CloudSubsystem
|
||||
|
||||
|
||||
class PlusSubsystem(AppSubsystem):
|
||||
class PlusAppSubsystem(AppSubsystem):
|
||||
"""Subsystem for plus functionality in the app.
|
||||
|
||||
The single shared instance of this app can be accessed at
|
||||
@ -1,6 +1,6 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Ballistica scene api version 1. Basically all gameplay related code."""
|
||||
"""Gameplay-centric api for classic BombSquad."""
|
||||
|
||||
# ba_meta require api 8
|
||||
|
||||
@ -18,6 +18,7 @@ import logging
|
||||
|
||||
from efro.util import set_canonical_module_names
|
||||
from babase import (
|
||||
add_clean_frame_callback,
|
||||
app,
|
||||
AppIntent,
|
||||
AppIntentDefault,
|
||||
@ -149,7 +150,6 @@ from _bascenev1 import (
|
||||
from bascenev1._activity import Activity
|
||||
from bascenev1._activitytypes import JoinActivity, ScoreScreenActivity
|
||||
from bascenev1._actor import Actor
|
||||
from bascenev1._appmode import SceneV1AppMode
|
||||
from bascenev1._campaign import init_campaigns, Campaign
|
||||
from bascenev1._collision import Collision, getcollision
|
||||
from bascenev1._coopgame import CoopGameActivity
|
||||
@ -249,6 +249,7 @@ __all__ = [
|
||||
'Actor',
|
||||
'animate',
|
||||
'animate_array',
|
||||
'add_clean_frame_callback',
|
||||
'app',
|
||||
'AppIntent',
|
||||
'AppIntentDefault',
|
||||
@ -410,7 +411,6 @@ __all__ = [
|
||||
'seek_replay',
|
||||
'safecolor',
|
||||
'screenmessage',
|
||||
'SceneV1AppMode',
|
||||
'ScoreConfig',
|
||||
'ScoreScreenActivity',
|
||||
'ScoreType',
|
||||
|
||||
@ -1,60 +0,0 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides AppMode functionality."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from bacommon.app import AppExperience
|
||||
from babase import (
|
||||
app,
|
||||
AppMode,
|
||||
AppIntentExec,
|
||||
AppIntentDefault,
|
||||
invoke_main_menu,
|
||||
)
|
||||
|
||||
import _bascenev1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from babase import AppIntent
|
||||
|
||||
|
||||
class SceneV1AppMode(AppMode):
|
||||
"""Our app-mode."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_app_experience(cls) -> AppExperience:
|
||||
return AppExperience.MELEE
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def _supports_intent(cls, intent: AppIntent) -> bool:
|
||||
# We support default and exec intents currently.
|
||||
return isinstance(intent, AppIntentExec | AppIntentDefault)
|
||||
|
||||
@override
|
||||
def handle_intent(self, intent: AppIntent) -> None:
|
||||
if isinstance(intent, AppIntentExec):
|
||||
_bascenev1.handle_app_intent_exec(intent.code)
|
||||
return
|
||||
assert isinstance(intent, AppIntentDefault)
|
||||
_bascenev1.handle_app_intent_default()
|
||||
|
||||
@override
|
||||
def on_activate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.on_app_mode_activate()
|
||||
|
||||
@override
|
||||
def on_deactivate(self) -> None:
|
||||
# Let the native layer do its thing.
|
||||
_bascenev1.on_app_mode_deactivate()
|
||||
|
||||
@override
|
||||
def on_app_active_changed(self) -> None:
|
||||
# If we've gone inactive, bring up the main menu, which has the
|
||||
# side effect of pausing the action (when possible).
|
||||
if not app.active:
|
||||
invoke_main_menu()
|
||||
@ -87,11 +87,19 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
||||
bascenev1.GameActivity.get_supported_maps() they can just rely on
|
||||
the default implementation here which calls those methods.
|
||||
"""
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.editgame import PlaylistEditGameWindow
|
||||
|
||||
assert babase.app.classic is not None
|
||||
delegate = babase.app.classic.delegate
|
||||
assert delegate is not None
|
||||
delegate.create_default_game_settings_ui(
|
||||
cls, sessiontype, settings, completion_call
|
||||
babase.app.ui_v1.clear_main_window()
|
||||
babase.app.ui_v1.set_main_window(
|
||||
PlaylistEditGameWindow(
|
||||
cls,
|
||||
sessiontype,
|
||||
settings,
|
||||
completion_call=completion_call,
|
||||
),
|
||||
from_window=False, # Disable check since we don't know.
|
||||
)
|
||||
|
||||
@classmethod
|
||||
@ -465,7 +473,7 @@ class GameActivity(Activity[PlayerT, TeamT]):
|
||||
# Only attempt this if we're not currently paused
|
||||
# and there appears to be no UI.
|
||||
assert babase.app.classic is not None
|
||||
hmmw = babase.app.ui_v1.has_main_menu_window()
|
||||
hmmw = babase.app.ui_v1.has_main_window()
|
||||
if not gnode.paused and not hmmw:
|
||||
self._is_waiting_for_continue = True
|
||||
with babase.ContextRef.empty():
|
||||
|
||||
@ -336,12 +336,13 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]):
|
||||
|
||||
def request_ui(self) -> None:
|
||||
"""Set up a callback to show our UI at the next opportune time."""
|
||||
assert bui.app.classic is not None
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
# We don't want to just show our UI in case the user already has the
|
||||
# main menu up, so instead we add a callback for when the menu
|
||||
# closes; if we're still alive, we'll come up then.
|
||||
# If there's no main menu this gets called immediately.
|
||||
bui.app.ui_v1.add_main_menu_close_callback(bui.WeakCall(self.show_ui))
|
||||
classic.add_main_menu_close_callback(bui.WeakCall(self.show_ui))
|
||||
|
||||
def show_ui(self) -> None:
|
||||
"""Show the UI for restarting, playing the next Level, etc."""
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Session and Activity for displaying the main menu bg."""
|
||||
# pylint: disable=too-many-lines
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
@ -48,48 +47,15 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
def on_transition_in(self) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-branches
|
||||
super().on_transition_in()
|
||||
random.seed(123)
|
||||
app = bs.app
|
||||
env = app.env
|
||||
assert app.classic is not None
|
||||
|
||||
plus = bui.app.plus
|
||||
plus = bs.app.plus
|
||||
assert plus is not None
|
||||
|
||||
# FIXME: We shouldn't be doing things conditionally based on whether
|
||||
# the host is VR mode or not (clients may differ in that regard).
|
||||
# Any differences need to happen at the engine level so everyone
|
||||
# sees things in their own optimal way.
|
||||
vr_mode = bs.app.env.vr
|
||||
|
||||
if not bs.app.ui_v1.use_toolbars:
|
||||
color = (1.0, 1.0, 1.0, 1.0) if vr_mode else (0.5, 0.6, 0.5, 0.6)
|
||||
|
||||
# FIXME: Need a node attr for vr-specific-scale.
|
||||
scale = (
|
||||
0.9
|
||||
if (app.ui_v1.uiscale is bs.UIScale.SMALL or vr_mode)
|
||||
else 0.7
|
||||
)
|
||||
self.my_name = bs.NodeActor(
|
||||
bs.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
'v_attach': 'bottom',
|
||||
'h_align': 'center',
|
||||
'color': color,
|
||||
'flatness': 1.0,
|
||||
'shadow': 1.0 if vr_mode else 0.5,
|
||||
'scale': scale,
|
||||
'position': (0, 10),
|
||||
'vr_depth': -10,
|
||||
'text': '\xa9 2011-2024 Eric Froemling',
|
||||
},
|
||||
)
|
||||
)
|
||||
|
||||
# Throw up some text that only clients can see so they know that the
|
||||
# host is navigating menus while they're just staring at an
|
||||
# empty-ish screen.
|
||||
@ -109,74 +75,17 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
},
|
||||
)
|
||||
)
|
||||
if not app.classic.main_menu_did_initial_transition and hasattr(
|
||||
self, 'my_name'
|
||||
if (
|
||||
not app.classic.main_menu_did_initial_transition
|
||||
and self.my_name is not None
|
||||
):
|
||||
assert self.my_name is not None
|
||||
assert self.my_name.node
|
||||
bs.animate(self.my_name.node, 'opacity', {2.3: 0, 3.0: 1.0})
|
||||
|
||||
# FIXME: We shouldn't be doing things conditionally based on whether
|
||||
# the host is vr mode or not (clients may not be or vice versa).
|
||||
# Any differences need to happen at the engine level so everyone sees
|
||||
# things in their own optimal way.
|
||||
vr_mode = app.env.vr
|
||||
uiscale = app.ui_v1.uiscale
|
||||
|
||||
# In cases where we're doing lots of dev work lets always show the
|
||||
# build number.
|
||||
force_show_build_number = False
|
||||
|
||||
if not bs.app.ui_v1.use_toolbars:
|
||||
if env.debug or env.test or force_show_build_number:
|
||||
if env.debug:
|
||||
text = bs.Lstr(
|
||||
value='${V} (${B}) (${D})',
|
||||
subs=[
|
||||
('${V}', app.env.engine_version),
|
||||
('${B}', str(app.env.engine_build_number)),
|
||||
('${D}', bs.Lstr(resource='debugText')),
|
||||
],
|
||||
)
|
||||
else:
|
||||
text = bs.Lstr(
|
||||
value='${V} (${B})',
|
||||
subs=[
|
||||
('${V}', app.env.engine_version),
|
||||
('${B}', str(app.env.engine_build_number)),
|
||||
],
|
||||
)
|
||||
else:
|
||||
text = bs.Lstr(
|
||||
value='${V}', subs=[('${V}', app.env.engine_version)]
|
||||
)
|
||||
scale = 0.9 if (uiscale is bs.UIScale.SMALL or vr_mode) else 0.7
|
||||
color = (1, 1, 1, 1) if vr_mode else (0.5, 0.6, 0.5, 0.7)
|
||||
self.version = bs.NodeActor(
|
||||
bs.newnode(
|
||||
'text',
|
||||
attrs={
|
||||
'v_attach': 'bottom',
|
||||
'h_attach': 'right',
|
||||
'h_align': 'right',
|
||||
'flatness': 1.0,
|
||||
'vr_depth': -10,
|
||||
'shadow': 1.0 if vr_mode else 0.5,
|
||||
'color': color,
|
||||
'scale': scale,
|
||||
'position': (-260, 10) if vr_mode else (-10, 10),
|
||||
'text': text,
|
||||
},
|
||||
)
|
||||
)
|
||||
if not app.classic.main_menu_did_initial_transition:
|
||||
assert self.version.node
|
||||
bs.animate(self.version.node, 'opacity', {2.3: 0, 3.0: 1.0})
|
||||
|
||||
# Throw in test build info.
|
||||
self.beta_info = self.beta_info_2 = None
|
||||
if env.test and not (env.demo or env.arcade):
|
||||
pos = (230, 35)
|
||||
if env.test:
|
||||
pos = (230, -5)
|
||||
self.beta_info = bs.NodeActor(
|
||||
bs.newnode(
|
||||
'text',
|
||||
@ -292,125 +201,20 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
self._update()
|
||||
|
||||
# Hopefully this won't hitch but lets space these out anyway.
|
||||
bui.add_clean_frame_callback(bs.WeakCall(self._start_preloads))
|
||||
bs.add_clean_frame_callback(bs.WeakCall(self._start_preloads))
|
||||
|
||||
random.seed()
|
||||
|
||||
if not (env.demo or env.arcade) and not app.ui_v1.use_toolbars:
|
||||
self._news = NewsDisplay(self)
|
||||
# Need to update this for toolbar mode; currenly doesn't fit.
|
||||
if bool(False):
|
||||
if not (env.demo or env.arcade):
|
||||
self._news = NewsDisplay(self)
|
||||
|
||||
self._attract_mode_timer = bs.Timer(
|
||||
3.12, self._update_attract_mode, repeat=True
|
||||
)
|
||||
|
||||
# Bring up the last place we were, or start at the main menu otherwise.
|
||||
with bs.ContextRef.empty():
|
||||
from bauiv1lib import specialoffer
|
||||
|
||||
assert bs.app.classic is not None
|
||||
if bui.app.env.headless:
|
||||
# UI stuff fails now in headless builds; avoid it.
|
||||
pass
|
||||
elif bool(False):
|
||||
uicontroller = bs.app.ui_v1.controller
|
||||
assert uicontroller is not None
|
||||
uicontroller.show_main_menu()
|
||||
else:
|
||||
main_menu_location = bs.app.ui_v1.get_main_menu_location()
|
||||
|
||||
# When coming back from a kiosk-mode game, jump to
|
||||
# the kiosk start screen.
|
||||
if env.demo or env.arcade:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.kiosk import KioskWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
KioskWindow().get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
# ..or in normal cases go back to the main menu
|
||||
else:
|
||||
if main_menu_location == 'Gather':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.gather import GatherWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Watch':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.watch import WatchWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
WatchWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Team Game Select':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.browser import (
|
||||
PlaylistBrowserWindow,
|
||||
)
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
PlaylistBrowserWindow(
|
||||
sessiontype=bs.DualTeamSession, transition=None
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Free-for-All Game Select':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.browser import (
|
||||
PlaylistBrowserWindow,
|
||||
)
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
PlaylistBrowserWindow(
|
||||
sessiontype=bs.FreeForAllSession,
|
||||
transition=None,
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Coop Select':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(
|
||||
transition=None
|
||||
).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
elif main_menu_location == 'Benchmarks & Stress Tests':
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.debug import DebugWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
DebugWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
else:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
bs.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition=None).get_root_widget(),
|
||||
from_window=False, # Disable check here.
|
||||
)
|
||||
|
||||
# attempt to show any pending offers immediately.
|
||||
# If that doesn't work, try again in a few seconds
|
||||
# (we may not have heard back from the server)
|
||||
# ..if that doesn't work they'll just have to wait
|
||||
# until the next opportunity.
|
||||
if not specialoffer.show_offer():
|
||||
|
||||
def try_again() -> None:
|
||||
if not specialoffer.show_offer():
|
||||
# Try one last time..
|
||||
bui.apptimer(2.0, specialoffer.show_offer)
|
||||
|
||||
bui.apptimer(2.0, try_again)
|
||||
app.classic.invoke_main_menu_ui()
|
||||
|
||||
app.classic.main_menu_did_initial_transition = True
|
||||
|
||||
@ -442,7 +246,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
lang = app.lang.language
|
||||
if lang != self._language:
|
||||
self._language = lang
|
||||
y = 20
|
||||
y = -15
|
||||
base_scale = 1.1
|
||||
self._word_actors = []
|
||||
base_delay = 1.0
|
||||
@ -536,7 +340,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
self._make_word(
|
||||
'B',
|
||||
x - 50,
|
||||
y - 23 + 0.8 * y_extra,
|
||||
y - 14 + 0.8 * y_extra,
|
||||
scale=1.3 * base_scale,
|
||||
delay=delay,
|
||||
vr_depth_offset=3,
|
||||
@ -568,7 +372,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
self._make_word(
|
||||
'S',
|
||||
x,
|
||||
y - 25 + 0.8 * y_extra,
|
||||
y - 15 + 0.8 * y_extra,
|
||||
scale=1.35 * base_scale,
|
||||
delay=delay,
|
||||
vr_depth_offset=14,
|
||||
@ -676,9 +480,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
)
|
||||
self._word_actors.append(word_obj)
|
||||
|
||||
# Add a bit of stop-motion-y jitter to the logo
|
||||
# (unless we're in VR mode in which case its best to
|
||||
# leave things still).
|
||||
# Add a bit of stop-motion-y jitter to the logo (unless we're in
|
||||
# VR mode in which case its best to leave things still).
|
||||
if not bs.app.env.vr:
|
||||
cmb: bs.Node | None
|
||||
cmb2: bs.Node | None
|
||||
@ -763,6 +566,7 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
vr_depth_offset: float = 0.0,
|
||||
) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
# Temp easter goodness.
|
||||
if custom_texture is None:
|
||||
custom_texture = self._get_custom_logo_tex_name()
|
||||
@ -794,9 +598,8 @@ class MainMenuActivity(bs.Activity[bs.Player, bs.Team]):
|
||||
self._logo_node = logo.node
|
||||
self._word_actors.append(logo)
|
||||
|
||||
# Add a bit of stop-motion-y jitter to the logo
|
||||
# (unless we're in VR mode in which case its best to
|
||||
# leave things still).
|
||||
# Add a bit of stop-motion-y jitter to the logo (unless we're in
|
||||
# VR mode in which case its best to leave things still).
|
||||
assert logo.node
|
||||
if not bs.app.env.vr:
|
||||
cmb = bs.newnode('combine', owner=logo.node, attrs={'size': 2})
|
||||
@ -879,8 +682,8 @@ class NewsDisplay:
|
||||
self._used_phrases: list[str] = []
|
||||
self._phrase_change_timer: bs.Timer | None = None
|
||||
|
||||
# If we're signed in, fetch news immediately.
|
||||
# Otherwise wait until we are signed in.
|
||||
# If we're signed in, fetch news immediately. Otherwise wait
|
||||
# until we are signed in.
|
||||
self._fetch_timer: bs.Timer | None = bs.Timer(
|
||||
1.0, bs.WeakCall(self._try_fetching_news), repeat=True
|
||||
)
|
||||
@ -913,8 +716,8 @@ class NewsDisplay:
|
||||
app = bs.app
|
||||
assert app.classic is not None
|
||||
|
||||
# If our news is way out of date, lets re-request it;
|
||||
# otherwise, rotate our phrase.
|
||||
# If our news is way out of date, lets re-request it; otherwise,
|
||||
# rotate our phrase.
|
||||
assert app.classic.main_menu_last_news_fetch_time is not None
|
||||
if time.time() - app.classic.main_menu_last_news_fetch_time > 600.0:
|
||||
self._fetch_news()
|
||||
@ -981,17 +784,16 @@ class NewsDisplay:
|
||||
self._text.node.text = val
|
||||
|
||||
def _got_news(self, news: str) -> None:
|
||||
# Run this stuff in the context of our activity since we
|
||||
# need to make nodes and stuff.. should fix the serverget
|
||||
# call so it.
|
||||
# Run this stuff in the context of our activity since we need to
|
||||
# make nodes and stuff.. should fix the serverget call so it.
|
||||
activity = self._activity()
|
||||
if activity is None or activity.expired:
|
||||
return
|
||||
with activity.context:
|
||||
self._phrases.clear()
|
||||
|
||||
# Show upcoming achievements in non-vr versions
|
||||
# (currently too hard to read in vr).
|
||||
# Show upcoming achievements in non-vr versions (currently
|
||||
# too hard to read in vr).
|
||||
self._used_phrases = (['__ACH__'] if not bs.app.env.vr else []) + [
|
||||
s for s in news.split('<br>\n') if s != ''
|
||||
]
|
||||
|
||||
@ -7,9 +7,9 @@
|
||||
# Package up various private bits (including stuff from our native
|
||||
# module) into a nice clean public API.
|
||||
from _batemplatefs import hello_again_world
|
||||
from batemplatefs._subsystem import TemplateFsSubsystem
|
||||
from batemplatefs._appsubsystem import TemplateFsAppSubsystem
|
||||
|
||||
__all__ = [
|
||||
'TemplateFsSubsystem',
|
||||
'TemplateFsAppSubsystem',
|
||||
'hello_again_world',
|
||||
]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides the TemplateFs subsystem."""
|
||||
"""Provides the TemplateFs App-Subsystem."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
@ -9,11 +9,11 @@ if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class TemplateFsSubsystem:
|
||||
class TemplateFsAppSubsystem:
|
||||
"""Subsystem for TemplateFs functionality in the app.
|
||||
|
||||
The single shared instance of this app can be accessed at
|
||||
babase.app.templatefs. Note that it is possible for babase.app.templatefs
|
||||
The single shared instance of this class can be accessed at
|
||||
ba*.app.templatefs. Note that it is possible for ba*.app.templatefs
|
||||
to be None if the TemplateFs feature-set is not enabled, and code
|
||||
should handle that case gracefully.
|
||||
"""
|
||||
@ -19,6 +19,7 @@ import logging
|
||||
from efro.util import set_canonical_module_names
|
||||
from babase import (
|
||||
add_clean_frame_callback,
|
||||
allows_ticket_sales,
|
||||
app,
|
||||
AppIntent,
|
||||
AppIntentDefault,
|
||||
@ -113,7 +114,6 @@ from _bauiv1 import (
|
||||
Mesh,
|
||||
rowwidget,
|
||||
scrollwidget,
|
||||
set_party_icon_always_visible,
|
||||
set_party_window_open,
|
||||
Sound,
|
||||
Texture,
|
||||
@ -123,11 +123,18 @@ from _bauiv1 import (
|
||||
widget,
|
||||
)
|
||||
from bauiv1._keyboard import Keyboard
|
||||
from bauiv1._uitypes import Window, uicleanupcheck
|
||||
from bauiv1._subsystem import UIV1Subsystem
|
||||
from bauiv1._uitypes import (
|
||||
Window,
|
||||
MainWindowState,
|
||||
BasicMainWindowState,
|
||||
uicleanupcheck,
|
||||
MainWindow,
|
||||
)
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
__all__ = [
|
||||
'add_clean_frame_callback',
|
||||
'allows_ticket_sales',
|
||||
'app',
|
||||
'AppIntent',
|
||||
'AppIntentDefault',
|
||||
@ -140,6 +147,7 @@ __all__ = [
|
||||
'AppTime',
|
||||
'apptimer',
|
||||
'AppTimer',
|
||||
'BasicMainWindowState',
|
||||
'buttonwidget',
|
||||
'Call',
|
||||
'fullscreen_control_available',
|
||||
@ -189,6 +197,8 @@ __all__ = [
|
||||
'LoginAdapter',
|
||||
'LoginInfo',
|
||||
'Lstr',
|
||||
'MainWindow',
|
||||
'MainWindowState',
|
||||
'Mesh',
|
||||
'native_review_request',
|
||||
'native_review_request_supported',
|
||||
@ -212,7 +222,6 @@ __all__ = [
|
||||
'scrollwidget',
|
||||
'set_analytics_screen',
|
||||
'set_low_level_config_value',
|
||||
'set_party_icon_always_visible',
|
||||
'set_party_window_open',
|
||||
'set_ui_input_device',
|
||||
'Sound',
|
||||
@ -225,7 +234,7 @@ __all__ = [
|
||||
'uibounds',
|
||||
'uicleanupcheck',
|
||||
'UIScale',
|
||||
'UIV1Subsystem',
|
||||
'UIV1AppSubsystem',
|
||||
'unlock_all_input',
|
||||
'WeakCall',
|
||||
'widget',
|
||||
|
||||
400
src/assets/ba_data/python/bauiv1/_appsubsystem.py
Normal file
400
src/assets/ba_data/python/bauiv1/_appsubsystem.py
Normal file
@ -0,0 +1,400 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""User interface related functionality."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import inspect
|
||||
import weakref
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from efro.util import empty_weakref
|
||||
import babase
|
||||
|
||||
import _bauiv1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
from bauiv1._uitypes import (
|
||||
UICleanupCheck,
|
||||
Window,
|
||||
MainWindow,
|
||||
MainWindowState,
|
||||
)
|
||||
import bauiv1
|
||||
|
||||
|
||||
class UIV1AppSubsystem(babase.AppSubsystem):
|
||||
"""Consolidated UI functionality for the app.
|
||||
|
||||
Category: **App Classes**
|
||||
|
||||
To use this class, access the single instance of it at 'ba.app.ui'.
|
||||
"""
|
||||
|
||||
class RootUIElement(Enum):
|
||||
"""Stuff provided by the root ui."""
|
||||
|
||||
MENU_BUTTON = 'menu_button'
|
||||
SQUAD_BUTTON = 'squad_button'
|
||||
ACCOUNT_BUTTON = 'account_button'
|
||||
SETTINGS_BUTTON = 'settings_button'
|
||||
INBOX_BUTTON = 'inbox_button'
|
||||
STORE_BUTTON = 'store_button'
|
||||
INVENTORY_BUTTON = 'inventory_button'
|
||||
ACHIEVEMENTS_BUTTON = 'achievements_button'
|
||||
GET_TOKENS_BUTTON = 'get_tokens_button'
|
||||
TICKETS_METER = 'tickets_meter'
|
||||
TOKENS_METER = 'tokens_meter'
|
||||
TROPHY_METER = 'trophy_meter'
|
||||
LEVEL_METER = 'level_meter'
|
||||
CHEST_SLOT_1 = 'chest_slot_1'
|
||||
CHEST_SLOT_2 = 'chest_slot_2'
|
||||
CHEST_SLOT_3 = 'chest_slot_3'
|
||||
CHEST_SLOT_4 = 'chest_slot_4'
|
||||
|
||||
def __init__(self) -> None:
|
||||
from bauiv1._uitypes import MainWindow
|
||||
|
||||
super().__init__()
|
||||
env = babase.env()
|
||||
|
||||
# We hold only a weak ref to the current main Window; we want it
|
||||
# to be able to disappear on its own. That being said, we do
|
||||
# expect MainWindows to keep themselves alive until replaced by
|
||||
# another MainWindow and we complain if they don't.
|
||||
self._main_window = empty_weakref(MainWindow)
|
||||
self._main_window_widget: bauiv1.Widget | None = None
|
||||
self.main_window_group_id: str | None = None
|
||||
|
||||
self.quit_window: bauiv1.Widget | None = None
|
||||
|
||||
# The following should probably go away or move to classic.
|
||||
# self._main_menu_location: str | None = None
|
||||
|
||||
# For storing arbitrary class-level state data for Windows or
|
||||
# other UI related classes.
|
||||
self.window_states: dict[type, Any] = {}
|
||||
|
||||
uiscalestr = babase.app.config.get('UI Scale', env['ui_scale'])
|
||||
if uiscalestr == 'auto':
|
||||
uiscalestr = env['ui_scale']
|
||||
|
||||
self._uiscale: babase.UIScale
|
||||
if uiscalestr == 'large':
|
||||
self._uiscale = babase.UIScale.LARGE
|
||||
elif uiscalestr == 'medium':
|
||||
self._uiscale = babase.UIScale.MEDIUM
|
||||
elif uiscalestr == 'small':
|
||||
self._uiscale = babase.UIScale.SMALL
|
||||
else:
|
||||
logging.error("Invalid UIScale '%s'.", uiscalestr)
|
||||
self._uiscale = babase.UIScale.MEDIUM
|
||||
|
||||
self.cleanupchecks: list[UICleanupCheck] = []
|
||||
self.upkeeptimer: babase.AppTimer | None = None
|
||||
|
||||
self.title_color = (0.72, 0.7, 0.75)
|
||||
self.heading_color = (0.72, 0.7, 0.75)
|
||||
self.infotextcolor = (0.7, 0.9, 0.7)
|
||||
|
||||
# Elements in our root UI will call anything here when activated.
|
||||
self.root_ui_calls: dict[
|
||||
UIV1AppSubsystem.RootUIElement, Callable[[], None]
|
||||
] = {}
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Can uiv1 currently be used?
|
||||
|
||||
Code that may run in headless mode, before the UI has been spun up,
|
||||
while other ui systems are active, etc. can check this to avoid
|
||||
likely erroring.
|
||||
"""
|
||||
return _bauiv1.is_available()
|
||||
|
||||
@override
|
||||
def reset(self) -> None:
|
||||
from bauiv1._uitypes import MainWindow
|
||||
|
||||
self.root_ui_calls.clear()
|
||||
self._main_window = empty_weakref(MainWindow)
|
||||
self._main_window_widget = None
|
||||
self.main_window_group_id = None
|
||||
|
||||
@property
|
||||
def uiscale(self) -> babase.UIScale:
|
||||
"""Current ui scale for the app."""
|
||||
return self._uiscale
|
||||
|
||||
@override
|
||||
def on_app_loading(self) -> None:
|
||||
from bauiv1._uitypes import ui_upkeep
|
||||
|
||||
# IMPORTANT: If tweaking UI stuff, make sure it behaves for small,
|
||||
# medium, and large UI modes. (doesn't run off screen, etc).
|
||||
# The overrides below can be used to test with different sizes.
|
||||
# Generally small is used on phones, medium is used on tablets/tvs,
|
||||
# and large is on desktop computers or perhaps large tablets. When
|
||||
# possible, run in windowed mode and resize the window to assure
|
||||
# this holds true at all aspect ratios.
|
||||
|
||||
# UPDATE: A better way to test this is now by setting the environment
|
||||
# variable BA_UI_SCALE to "small", "medium", or "large".
|
||||
# This will affect system UIs not covered by the values below such
|
||||
# as screen-messages. The below values remain functional, however,
|
||||
# for cases such as Android where environment variables can't be set
|
||||
# easily.
|
||||
|
||||
if bool(False): # force-test ui scale
|
||||
self._uiscale = babase.UIScale.SMALL
|
||||
with babase.ContextRef.empty():
|
||||
babase.pushcall(
|
||||
lambda: babase.screenmessage(
|
||||
f'FORCING UISCALE {self._uiscale.name} FOR TESTING',
|
||||
color=(1, 0, 1),
|
||||
log=True,
|
||||
)
|
||||
)
|
||||
|
||||
# Kick off our periodic UI upkeep.
|
||||
# FIXME: Can probably kill this if we do immediate UI death checks.
|
||||
self.upkeeptimer = babase.AppTimer(2.6543, ui_upkeep, repeat=True)
|
||||
|
||||
def do_main_window_back(self, window: MainWindow) -> None:
|
||||
"""Sets the main menu window automatically from a parent WindowState."""
|
||||
|
||||
main_window = self._main_window()
|
||||
back_state = (
|
||||
None if main_window is None else main_window.main_window_back_state
|
||||
)
|
||||
if back_state is None:
|
||||
raise RuntimeError(
|
||||
f'Main window {main_window} provides no back-state;'
|
||||
f' cannot use auto-back.'
|
||||
)
|
||||
backwin = back_state.create_window(transition='in_left')
|
||||
backwin.main_window_back_state = back_state.parent
|
||||
self.set_main_window(backwin, from_window=window, is_back=True)
|
||||
|
||||
def get_main_window(self) -> bauiv1.MainWindow | None:
|
||||
"""Return main window, if any."""
|
||||
return self._main_window()
|
||||
|
||||
def set_main_window(
|
||||
self,
|
||||
window: bauiv1.MainWindow,
|
||||
from_window: bauiv1.MainWindow | None | bool = True,
|
||||
is_back: bool = False,
|
||||
group_id: str | None = None,
|
||||
is_top_level: bool = False,
|
||||
back_state: MainWindowState | None = None,
|
||||
) -> None:
|
||||
"""Set the current 'main' window, replacing any existing.
|
||||
|
||||
If 'from_window' is passed as a bauiv1.Widget or bauiv1.Window
|
||||
or None, a warning will be issued if it that value does not
|
||||
match the current main window. This can help identify flawed
|
||||
code that can lead to bad UI states. A value of False will
|
||||
disable the check, which is necessary in some cases when the
|
||||
current main window is not known.
|
||||
|
||||
When navigating somewhere from a cancel or back-button, pass
|
||||
is_back=True; this will prevent the new main window from itself
|
||||
being registered as a new location on the stack that can be
|
||||
returned to.
|
||||
|
||||
If a 'group_id' string is provided and the window being replaced
|
||||
has the same group-id, the WindowState stack is left unchanged,
|
||||
effectively replacing the previous window with the new one in
|
||||
the stack. This can be useful in cases where tab-bar-like UIs
|
||||
allow flipping between sibling windows with the back button
|
||||
always leading to a shared parent.
|
||||
"""
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
from bauiv1._uitypes import MainWindow
|
||||
|
||||
from_window_widget: bauiv1.Widget | None
|
||||
|
||||
# We used to accept Widgets but now want MainWindows.
|
||||
assert isinstance(window, MainWindow)
|
||||
window_weakref = weakref.ref(window)
|
||||
window_widget = window.get_root_widget()
|
||||
|
||||
if isinstance(from_window, MainWindow):
|
||||
from_window_widget = from_window.get_root_widget()
|
||||
else:
|
||||
from_window_widget = None
|
||||
|
||||
existing = self._main_window_widget
|
||||
|
||||
try:
|
||||
if isinstance(from_window, bool):
|
||||
# For default val True we warn that the arg wasn't
|
||||
# passed. False can be explicitly passed to disable this
|
||||
# check.
|
||||
if from_window is True:
|
||||
caller_frame = inspect.stack()[1]
|
||||
caller_filename = caller_frame.filename
|
||||
caller_line_number = caller_frame.lineno
|
||||
logging.warning(
|
||||
'set_main_window() should be passed a'
|
||||
" 'from_window' value to help ensure proper UI behavior"
|
||||
' (%s line %i).',
|
||||
caller_filename,
|
||||
caller_line_number,
|
||||
)
|
||||
else:
|
||||
# For everything else, warn if what they passed wasn't
|
||||
# the previous main menu widget.
|
||||
if from_window_widget is not existing:
|
||||
caller_frame = inspect.stack()[1]
|
||||
caller_filename = caller_frame.filename
|
||||
caller_line_number = caller_frame.lineno
|
||||
logging.warning(
|
||||
"set_main_window() was passed 'from_window' %s"
|
||||
' but existing main-menu-window is %s. (%s line %i).',
|
||||
from_window_widget,
|
||||
existing,
|
||||
caller_filename,
|
||||
caller_line_number,
|
||||
)
|
||||
except Exception:
|
||||
# Prevent any bugs in these checks from causing problems.
|
||||
logging.exception('Error checking from_window')
|
||||
|
||||
# Once the above code leads to us fixing all leftover window
|
||||
# bugs at the source, we can kill the code below.
|
||||
|
||||
# Let's grab the location where we were called from to report if
|
||||
# we have to force-kill the existing window (which normally
|
||||
# should not happen).
|
||||
frameline = None
|
||||
try:
|
||||
frame = inspect.currentframe()
|
||||
if frame is not None:
|
||||
frame = frame.f_back
|
||||
if frame is not None:
|
||||
frameinfo = inspect.getframeinfo(frame)
|
||||
frameline = f'{frameinfo.filename} {frameinfo.lineno}'
|
||||
except Exception:
|
||||
logging.exception('Error calcing line for set_main_window')
|
||||
|
||||
# NOTE: disabling this for now since hopefully our new system
|
||||
# will be bulletproof enough to avoid this. Can turn it back on
|
||||
# if that's not the case.
|
||||
|
||||
# With our legacy main-menu system, the caller is responsible
|
||||
# for clearing out the old main menu window when assigning the
|
||||
# new. However there are corner cases where that doesn't happen
|
||||
# and we get old windows stuck under the new main one. So let's
|
||||
# guard against that. However, we can't simply delete the
|
||||
# existing main window when a new one is assigned because the
|
||||
# user may transition the old out *after* the assignment. Sigh.
|
||||
# So, as a happy medium, let's check in on the old after a short
|
||||
# bit of time and kill it if its still alive. That will be a bit
|
||||
# ugly on screen but at least should un-break things.
|
||||
def _delay_kill() -> None:
|
||||
import time
|
||||
|
||||
if existing:
|
||||
print(
|
||||
f'Killing old main_menu_window'
|
||||
f' when called at: {frameline} t={time.time():.3f}'
|
||||
)
|
||||
existing.delete()
|
||||
|
||||
if bool(False):
|
||||
babase.apptimer(1.0, _delay_kill)
|
||||
|
||||
if is_back:
|
||||
pass
|
||||
else:
|
||||
# When navigating forward, generate a back-window-state from
|
||||
# the outgoing window.
|
||||
|
||||
# Exception is when we were passed a group and it matches
|
||||
# the existing group; in that case we just keep the existing
|
||||
# back-state.
|
||||
if group_id is not None and group_id == self.main_window_group_id:
|
||||
assert not is_top_level
|
||||
print(f'GOT GROUP ID MATCH {group_id}; KEEPING BACK STATE.')
|
||||
oldwin = self._main_window()
|
||||
if oldwin is None:
|
||||
# We currenty only hold weak refs to windows so
|
||||
# that they are free to die on their own, but we
|
||||
# expect the main menu window to keep itself
|
||||
# alive as long as its the main one. Holler if
|
||||
# that seems to not be happening.
|
||||
logging.warning(
|
||||
'set_main_window: no existing MainWindow found'
|
||||
' (and is_top_level is False); should not happen.'
|
||||
' a MainWindow should keep itself alive as long'
|
||||
' as it is main.'
|
||||
)
|
||||
window.main_window_back_state = None
|
||||
else:
|
||||
window.main_window_back_state = (
|
||||
oldwin.main_window_back_state
|
||||
)
|
||||
else:
|
||||
if is_top_level:
|
||||
# Top level windows don't have or expect anywhere to go
|
||||
# back to.
|
||||
# self._main_window_back_state = None
|
||||
window.main_window_back_state = None
|
||||
elif back_state is not None:
|
||||
window.main_window_back_state = back_state
|
||||
else:
|
||||
oldwin = self._main_window()
|
||||
if oldwin is None:
|
||||
# We currenty only hold weak refs to windows so
|
||||
# that they are free to die on their own, but we
|
||||
# expect the main menu window to keep itself
|
||||
# alive as long as its the main one. Holler if
|
||||
# that seems to not be happening.
|
||||
logging.warning(
|
||||
'set_main_window: No old MainWindow found'
|
||||
' and is_top_level is False;'
|
||||
' this should not happen.'
|
||||
)
|
||||
window.main_window_back_state = None
|
||||
else:
|
||||
oldwinstate = oldwin.get_main_window_state()
|
||||
|
||||
# Store our previous back state on this new one.
|
||||
oldwinstate.parent = oldwin.main_window_back_state
|
||||
window.main_window_back_state = oldwinstate
|
||||
|
||||
self._main_window = window_weakref
|
||||
self._main_window_widget = window_widget
|
||||
self.main_window_group_id = group_id
|
||||
|
||||
def has_main_window(self) -> bool:
|
||||
"""Return whether a main menu window is present."""
|
||||
return bool(self._main_window_widget)
|
||||
|
||||
def clear_main_window(self) -> None:
|
||||
"""Clear any existing main window."""
|
||||
from bauiv1._uitypes import MainWindow
|
||||
|
||||
main_window = self._main_window()
|
||||
if main_window:
|
||||
main_window.main_window_close()
|
||||
else:
|
||||
# Fallback; if we have a widget but no window, nuke the widget.
|
||||
if self._main_window_widget:
|
||||
logging.error(
|
||||
'Have _main_window_widget but no main_window'
|
||||
' on clear_main_window; unexpected.'
|
||||
)
|
||||
self._main_window_widget.delete()
|
||||
|
||||
self._main_window = empty_weakref(MainWindow)
|
||||
self._main_window_widget = None
|
||||
self.main_window_group_id = None
|
||||
@ -15,49 +15,130 @@ if TYPE_CHECKING:
|
||||
from typing import Sequence
|
||||
|
||||
import babase
|
||||
|
||||
|
||||
def ticket_icon_press() -> None:
|
||||
from babase import app
|
||||
|
||||
if app.classic is None:
|
||||
logging.exception('Classic not present.')
|
||||
return
|
||||
|
||||
app.classic.ticket_icon_press()
|
||||
|
||||
|
||||
def trophy_icon_press() -> None:
|
||||
print('TROPHY ICON PRESSED')
|
||||
|
||||
|
||||
def level_icon_press() -> None:
|
||||
print('LEVEL ICON PRESSED')
|
||||
|
||||
|
||||
def coin_icon_press() -> None:
|
||||
print('COIN ICON PRESSED')
|
||||
import bauiv1
|
||||
|
||||
|
||||
def empty_call() -> None:
|
||||
pass
|
||||
|
||||
|
||||
def back_button_press() -> None:
|
||||
_bauiv1.back_press()
|
||||
def _root_ui_button_press(
|
||||
rootuitype: bauiv1.UIV1AppSubsystem.RootUIElement,
|
||||
) -> None:
|
||||
import babase
|
||||
|
||||
ui = babase.app.ui_v1
|
||||
call = ui.root_ui_calls.get(rootuitype)
|
||||
if call is not None:
|
||||
call()
|
||||
|
||||
|
||||
def friends_button_press() -> None:
|
||||
print('FRIEND BUTTON PRESSED!')
|
||||
def root_ui_account_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.ACCOUNT_BUTTON)
|
||||
|
||||
|
||||
def party_icon_activate(origin: Sequence[float]) -> None:
|
||||
from babase import app
|
||||
def root_ui_inbox_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
if app.classic is not None:
|
||||
app.classic.party_icon_activate(origin)
|
||||
else:
|
||||
logging.warning('party_icon_activate: no classic.')
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.INBOX_BUTTON)
|
||||
|
||||
|
||||
def root_ui_settings_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.SETTINGS_BUTTON)
|
||||
|
||||
|
||||
def root_ui_achievements_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.ACHIEVEMENTS_BUTTON)
|
||||
|
||||
|
||||
def root_ui_store_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.STORE_BUTTON)
|
||||
|
||||
|
||||
def root_ui_chest_slot_1_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.CHEST_SLOT_1)
|
||||
|
||||
|
||||
def root_ui_chest_slot_2_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.CHEST_SLOT_2)
|
||||
|
||||
|
||||
def root_ui_chest_slot_3_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.CHEST_SLOT_3)
|
||||
|
||||
|
||||
def root_ui_chest_slot_4_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.CHEST_SLOT_4)
|
||||
|
||||
|
||||
def root_ui_inventory_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.INVENTORY_BUTTON)
|
||||
|
||||
|
||||
def root_ui_ticket_icon_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.TICKETS_METER)
|
||||
|
||||
|
||||
def root_ui_get_tokens_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.GET_TOKENS_BUTTON)
|
||||
|
||||
|
||||
def root_ui_tokens_meter_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.TOKENS_METER)
|
||||
|
||||
|
||||
def root_ui_trophy_meter_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.TROPHY_METER)
|
||||
|
||||
|
||||
def root_ui_level_icon_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.LEVEL_METER)
|
||||
|
||||
|
||||
def root_ui_menu_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.MENU_BUTTON)
|
||||
|
||||
|
||||
def root_ui_back_button_press() -> None:
|
||||
# Native layer handles this directly. (technically we could wire
|
||||
# this up to not even come through Python).
|
||||
_bauiv1.root_ui_back_press()
|
||||
|
||||
|
||||
def root_ui_squad_button_press() -> None:
|
||||
from bauiv1._appsubsystem import UIV1AppSubsystem
|
||||
|
||||
_root_ui_button_press(UIV1AppSubsystem.RootUIElement.SQUAD_BUTTON)
|
||||
|
||||
|
||||
def quit_window(quit_type: babase.QuitType) -> None:
|
||||
|
||||
@ -1,250 +0,0 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""User interface related functionality."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import inspect
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import babase
|
||||
|
||||
import _bauiv1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
from bauiv1._uitypes import UICleanupCheck, UIController
|
||||
import bauiv1
|
||||
|
||||
|
||||
class UIV1Subsystem(babase.AppSubsystem):
|
||||
"""Consolidated UI functionality for the app.
|
||||
|
||||
Category: **App Classes**
|
||||
|
||||
To use this class, access the single instance of it at 'ba.app.ui'.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
env = babase.env()
|
||||
|
||||
self.controller: UIController | None = None
|
||||
|
||||
self._main_menu_window: bauiv1.Widget | None = None
|
||||
self._main_menu_location: str | None = None
|
||||
self.quit_window: bauiv1.Widget | None = None
|
||||
|
||||
# From classic.
|
||||
self.main_menu_resume_callbacks: list = [] # Can probably go away.
|
||||
|
||||
self._uiscale: babase.UIScale
|
||||
|
||||
interfacetype = babase.app.config.get('UI Scale', env['ui_scale'])
|
||||
if interfacetype == 'auto':
|
||||
interfacetype = env['ui_scale']
|
||||
|
||||
if interfacetype == 'large':
|
||||
self._uiscale = babase.UIScale.LARGE
|
||||
elif interfacetype == 'medium':
|
||||
self._uiscale = babase.UIScale.MEDIUM
|
||||
elif interfacetype == 'small':
|
||||
self._uiscale = babase.UIScale.SMALL
|
||||
else:
|
||||
raise RuntimeError(f'Invalid UIScale value: {interfacetype}')
|
||||
|
||||
self.window_states: dict[type, Any] = {} # FIXME: Kill this.
|
||||
self.main_menu_selection: str | None = None # FIXME: Kill this.
|
||||
self.have_party_queue_window = False
|
||||
self.cleanupchecks: list[UICleanupCheck] = []
|
||||
self.upkeeptimer: babase.AppTimer | None = None
|
||||
self.use_toolbars = _bauiv1.toolbar_test()
|
||||
|
||||
self.title_color = (0.72, 0.7, 0.75)
|
||||
self.heading_color = (0.72, 0.7, 0.75)
|
||||
self.infotextcolor = (0.7, 0.9, 0.7)
|
||||
|
||||
# Switch our overall game selection UI flow between Play and
|
||||
# Private-party playlist selection modes; should do this in
|
||||
# a more elegant way once we revamp high level UI stuff a bit.
|
||||
self.selecting_private_party_playlist: bool = False
|
||||
|
||||
@property
|
||||
def available(self) -> bool:
|
||||
"""Can uiv1 currently be used?
|
||||
|
||||
Code that may run in headless mode, before the UI has been spun up,
|
||||
while other ui systems are active, etc. can check this to avoid
|
||||
likely erroring.
|
||||
"""
|
||||
return _bauiv1.is_available()
|
||||
|
||||
@property
|
||||
def uiscale(self) -> babase.UIScale:
|
||||
"""Current ui scale for the app."""
|
||||
return self._uiscale
|
||||
|
||||
@override
|
||||
def on_app_loading(self) -> None:
|
||||
from bauiv1._uitypes import UIController, ui_upkeep
|
||||
|
||||
# IMPORTANT: If tweaking UI stuff, make sure it behaves for small,
|
||||
# medium, and large UI modes. (doesn't run off screen, etc).
|
||||
# The overrides below can be used to test with different sizes.
|
||||
# Generally small is used on phones, medium is used on tablets/tvs,
|
||||
# and large is on desktop computers or perhaps large tablets. When
|
||||
# possible, run in windowed mode and resize the window to assure
|
||||
# this holds true at all aspect ratios.
|
||||
|
||||
# UPDATE: A better way to test this is now by setting the environment
|
||||
# variable BA_UI_SCALE to "small", "medium", or "large".
|
||||
# This will affect system UIs not covered by the values below such
|
||||
# as screen-messages. The below values remain functional, however,
|
||||
# for cases such as Android where environment variables can't be set
|
||||
# easily.
|
||||
|
||||
if bool(False): # force-test ui scale
|
||||
self._uiscale = babase.UIScale.SMALL
|
||||
with babase.ContextRef.empty():
|
||||
babase.pushcall(
|
||||
lambda: babase.screenmessage(
|
||||
f'FORCING UISCALE {self._uiscale.name} FOR TESTING',
|
||||
color=(1, 0, 1),
|
||||
log=True,
|
||||
)
|
||||
)
|
||||
|
||||
self.controller = UIController()
|
||||
|
||||
# Kick off our periodic UI upkeep.
|
||||
# FIXME: Can probably kill this if we do immediate UI death checks.
|
||||
self.upkeeptimer = babase.AppTimer(2.6543, ui_upkeep, repeat=True)
|
||||
|
||||
def set_main_menu_window(
|
||||
self,
|
||||
window: bauiv1.Widget,
|
||||
from_window: bauiv1.Widget | None | bool = True,
|
||||
) -> None:
|
||||
"""Set the current 'main' window, replacing any existing.
|
||||
|
||||
If 'from_window' is passed as a bauiv1.Widget or None, a warning
|
||||
will be issued if it that value does not match the current main
|
||||
window. This can help clean up flawed code that can lead to bad
|
||||
UI states. A value of False will disable the check.
|
||||
"""
|
||||
|
||||
existing = self._main_menu_window
|
||||
|
||||
try:
|
||||
if isinstance(from_window, bool):
|
||||
# For default val True we warn that the arg wasn't
|
||||
# passed. False can be explicitly passed to disable this
|
||||
# check.
|
||||
if from_window is True:
|
||||
caller_frame = inspect.stack()[1]
|
||||
caller_filename = caller_frame.filename
|
||||
caller_line_number = caller_frame.lineno
|
||||
logging.warning(
|
||||
'set_main_menu_window() should be passed a'
|
||||
" 'from_window' value to help ensure proper UI behavior"
|
||||
' (%s line %i).',
|
||||
caller_filename,
|
||||
caller_line_number,
|
||||
)
|
||||
else:
|
||||
# For everything else, warn if what they passed wasn't
|
||||
# the previous main menu widget.
|
||||
if from_window is not existing:
|
||||
caller_frame = inspect.stack()[1]
|
||||
caller_filename = caller_frame.filename
|
||||
caller_line_number = caller_frame.lineno
|
||||
logging.warning(
|
||||
"set_main_menu_window() was passed 'from_window' %s"
|
||||
' but existing main-menu-window is %s. (%s line %i).',
|
||||
from_window,
|
||||
existing,
|
||||
caller_filename,
|
||||
caller_line_number,
|
||||
)
|
||||
except Exception:
|
||||
# Prevent any bugs in these checks from causing problems.
|
||||
logging.exception('Error checking from_window')
|
||||
|
||||
# Once the above code leads to us fixing all leftover window bugs
|
||||
# at the source, we can kill the code below.
|
||||
|
||||
# Let's grab the location where we were called from to report
|
||||
# if we have to force-kill the existing window (which normally
|
||||
# should not happen).
|
||||
frameline = None
|
||||
try:
|
||||
frame = inspect.currentframe()
|
||||
if frame is not None:
|
||||
frame = frame.f_back
|
||||
if frame is not None:
|
||||
frameinfo = inspect.getframeinfo(frame)
|
||||
frameline = f'{frameinfo.filename} {frameinfo.lineno}'
|
||||
except Exception:
|
||||
logging.exception('Error calcing line for set_main_menu_window')
|
||||
|
||||
# With our legacy main-menu system, the caller is responsible for
|
||||
# clearing out the old main menu window when assigning the new.
|
||||
# However there are corner cases where that doesn't happen and we get
|
||||
# old windows stuck under the new main one. So let's guard against
|
||||
# that. However, we can't simply delete the existing main window when
|
||||
# a new one is assigned because the user may transition the old out
|
||||
# *after* the assignment. Sigh. So, as a happy medium, let's check in
|
||||
# on the old after a short bit of time and kill it if its still alive.
|
||||
# That will be a bit ugly on screen but at least should un-break
|
||||
# things.
|
||||
def _delay_kill() -> None:
|
||||
import time
|
||||
|
||||
if existing:
|
||||
print(
|
||||
f'Killing old main_menu_window'
|
||||
f' when called at: {frameline} t={time.time():.3f}'
|
||||
)
|
||||
existing.delete()
|
||||
|
||||
babase.apptimer(1.0, _delay_kill)
|
||||
self._main_menu_window = window
|
||||
|
||||
def clear_main_menu_window(self, transition: str | None = None) -> None:
|
||||
"""Clear any existing 'main' window with the provided transition."""
|
||||
assert transition is None or not transition.endswith('_in')
|
||||
if self._main_menu_window:
|
||||
if (
|
||||
transition is not None
|
||||
and not self._main_menu_window.transitioning_out
|
||||
):
|
||||
_bauiv1.containerwidget(
|
||||
edit=self._main_menu_window, transition=transition
|
||||
)
|
||||
else:
|
||||
self._main_menu_window.delete()
|
||||
self._main_menu_window = None
|
||||
|
||||
def add_main_menu_close_callback(self, call: Callable[[], Any]) -> None:
|
||||
"""(internal)"""
|
||||
|
||||
# If there's no main menu up, just call immediately.
|
||||
if not self.has_main_menu_window():
|
||||
with babase.ContextRef.empty():
|
||||
call()
|
||||
else:
|
||||
self.main_menu_resume_callbacks.append(call)
|
||||
|
||||
def has_main_menu_window(self) -> bool:
|
||||
"""Return whether a main menu window is present."""
|
||||
return bool(self._main_menu_window)
|
||||
|
||||
def set_main_menu_location(self, location: str) -> None:
|
||||
"""Set the location represented by the current main menu window."""
|
||||
self._main_menu_location = location
|
||||
|
||||
def get_main_menu_location(self) -> str | None:
|
||||
"""Return the current named main menu location, if any."""
|
||||
return self._main_menu_location
|
||||
@ -6,6 +6,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import weakref
|
||||
import logging
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
@ -14,7 +15,7 @@ import babase
|
||||
import _bauiv1
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Type
|
||||
from typing import Any, Type, Literal, Callable
|
||||
|
||||
import bauiv1
|
||||
|
||||
@ -27,6 +28,9 @@ class Window:
|
||||
"""A basic window.
|
||||
|
||||
Category: User Interface Classes
|
||||
|
||||
Essentially wraps a ContainerWidget with some higher level
|
||||
functionality.
|
||||
"""
|
||||
|
||||
def __init__(self, root_widget: bauiv1.Widget, cleanupcheck: bool = True):
|
||||
@ -41,6 +45,192 @@ class Window:
|
||||
return self._root_widget
|
||||
|
||||
|
||||
class MainWindow(Window):
|
||||
"""A special window that can be used as a main window."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
root_widget: bauiv1.Widget,
|
||||
transition: str | None,
|
||||
origin_widget: bauiv1.Widget | None,
|
||||
cleanupcheck: bool = True,
|
||||
):
|
||||
"""Create a MainWindow given a root widget and transition info.
|
||||
|
||||
Automatically handles in and out transitions on the provided widget,
|
||||
so there is no need to set transitions when creating it.
|
||||
"""
|
||||
# TODO - move to MainWindow
|
||||
# A back-state supplied by the ui system.
|
||||
self.main_window_back_state: MainWindowState | None = None
|
||||
|
||||
self._main_window_transition = transition
|
||||
self._main_window_origin_widget = origin_widget
|
||||
super().__init__(root_widget, cleanupcheck)
|
||||
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._main_window_transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._main_window_transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
_bauiv1.containerwidget(
|
||||
edit=root_widget,
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
)
|
||||
|
||||
def main_window_close(self) -> None:
|
||||
"""Get window transitioning out if still alive."""
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
# Transition ourself out.
|
||||
try:
|
||||
self.on_main_window_close()
|
||||
except Exception:
|
||||
logging.exception('Error in on_main_window_close() for %s.', self)
|
||||
|
||||
_bauiv1.containerwidget(
|
||||
edit=self._root_widget, transition=self._main_window_transition_out
|
||||
)
|
||||
|
||||
def can_change_main_window(self) -> bool:
|
||||
"""Is this MainWindow allowed to change the global main window?
|
||||
|
||||
It is a good idea to make sure this is True before calling
|
||||
either main_window_back() or main_window_replace(). This
|
||||
prevents fluke UI breakage such as multiple simultaneous events
|
||||
causing a MainWindow to spawn multiple replacements for itself.
|
||||
"""
|
||||
# We are allowed to change main windows if we are the current one
|
||||
# AND our underlying widget is still alive and not transitioning out.
|
||||
return (
|
||||
babase.app.ui_v1.get_main_window() is self
|
||||
and bool(self._root_widget)
|
||||
and not self._root_widget.transitioning_out
|
||||
)
|
||||
|
||||
def main_window_back(self) -> None:
|
||||
"""Move back in the main window stack."""
|
||||
|
||||
# Users should always check can_change_main_window() before
|
||||
# calling us. Error if it seems they did not.
|
||||
if not self.can_change_main_window():
|
||||
raise RuntimeError(
|
||||
'main_window_back() should only be called'
|
||||
' if can_change_main_window() returns True'
|
||||
' (it currently is False).'
|
||||
)
|
||||
|
||||
# Get the 'back' window coming in.
|
||||
babase.app.ui_v1.do_main_window_back(self)
|
||||
|
||||
self.main_window_close()
|
||||
|
||||
def main_window_replace(
|
||||
self, new_window: MainWindow, group_id: str | None = None
|
||||
) -> None:
|
||||
"""Replace ourself with a new MainWindow."""
|
||||
|
||||
# Users should always check can_change_main_window() before
|
||||
# creating new MainWindows and passing them in here. Error if it
|
||||
# seems they did not.
|
||||
if not self.can_change_main_window():
|
||||
raise RuntimeError(
|
||||
'main_window_replace() should only be called'
|
||||
' if can_change_main_window() returns True'
|
||||
' (it currently is False).'
|
||||
)
|
||||
|
||||
# If we're navigating within a group, we want it to look like we're
|
||||
# backing out of the old one and going into the new one.
|
||||
if (
|
||||
group_id is not None
|
||||
and babase.app.ui_v1.main_window_group_id == group_id
|
||||
):
|
||||
transition = self._main_window_transition_out
|
||||
else:
|
||||
# Otherwise just shove the old out the left to give the feel
|
||||
# that we're adding to the nav stack.
|
||||
transition = 'out_left'
|
||||
|
||||
# Transition ourself out.
|
||||
try:
|
||||
self.on_main_window_close()
|
||||
except Exception:
|
||||
logging.exception('Error in on_main_window_close() for %s.', self)
|
||||
|
||||
_bauiv1.containerwidget(edit=self._root_widget, transition=transition)
|
||||
babase.app.ui_v1.set_main_window(
|
||||
new_window, from_window=self, group_id=group_id
|
||||
)
|
||||
|
||||
def on_main_window_close(self) -> None:
|
||||
"""Called before transitioning out a main window.
|
||||
|
||||
A good opportunity to save window state/etc.
|
||||
"""
|
||||
|
||||
def get_main_window_state(self) -> MainWindowState:
|
||||
"""Return a WindowState to recreate this window, if supported."""
|
||||
# TODO - change to NotImplementedError when moved to MainWindow.
|
||||
raise RuntimeError('FIXME NOT IMPLEMENTED')
|
||||
|
||||
|
||||
class MainWindowState:
|
||||
"""Persistent state for a specific main-window and its ancestors.
|
||||
|
||||
This allows MainWindows to be automatically recreated for back-button
|
||||
purposes, when switching app-modes, etc.
|
||||
"""
|
||||
|
||||
def __init__(self, parent: MainWindowState | None = None) -> None:
|
||||
# The window that back/cancel navigation should take us to.
|
||||
self.parent = parent
|
||||
|
||||
def create_window(
|
||||
self,
|
||||
transition: Literal['in_right', 'in_left', 'in_scale'] | None = None,
|
||||
origin_widget: bauiv1.Widget | None = None,
|
||||
) -> MainWindow:
|
||||
"""Create a window based on this state.
|
||||
|
||||
WindowState child classes should override this to recreate their
|
||||
particular type of window.
|
||||
"""
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
class BasicMainWindowState(MainWindowState):
|
||||
"""A basic MainWindowState holding a lambda to recreate a MainWindow."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
create_call: Callable[
|
||||
[
|
||||
Literal['in_right', 'in_left', 'in_scale'] | None,
|
||||
bauiv1.Widget | None,
|
||||
],
|
||||
bauiv1.MainWindow,
|
||||
],
|
||||
) -> None:
|
||||
super().__init__()
|
||||
self.create_call = create_call
|
||||
|
||||
@override
|
||||
def create_window(
|
||||
self,
|
||||
transition: Literal['in_right', 'in_left', 'in_scale'] | None = None,
|
||||
origin_widget: bauiv1.Widget | None = None,
|
||||
) -> bauiv1.MainWindow:
|
||||
return self.create_call(transition, origin_widget)
|
||||
|
||||
|
||||
@dataclass
|
||||
class UICleanupCheck:
|
||||
"""Holds info about a uicleanupcheck target."""
|
||||
@ -50,127 +240,8 @@ class UICleanupCheck:
|
||||
widget_death_time: float | None
|
||||
|
||||
|
||||
class UILocation:
|
||||
"""Defines a specific 'place' in the UI the user can navigate to.
|
||||
|
||||
Category: User Interface Classes
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
pass
|
||||
|
||||
def save_state(self) -> None:
|
||||
"""Serialize this instance's state to a dict."""
|
||||
|
||||
def restore_state(self) -> None:
|
||||
"""Restore this instance's state from a dict."""
|
||||
|
||||
def push_location(self, location: str) -> None:
|
||||
"""Push a new location to the stack and transition to it."""
|
||||
|
||||
|
||||
class UILocationWindow(UILocation):
|
||||
"""A UILocation consisting of a single root window widget.
|
||||
|
||||
Category: User Interface Classes
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._root_widget: bauiv1.Widget | None = None
|
||||
|
||||
def get_root_widget(self) -> bauiv1.Widget:
|
||||
"""Return the root widget for this window."""
|
||||
assert self._root_widget is not None
|
||||
return self._root_widget
|
||||
|
||||
|
||||
class UIEntry:
|
||||
"""State for a UILocation on the stack."""
|
||||
|
||||
def __init__(self, name: str, controller: UIController):
|
||||
self._name = name
|
||||
self._state = None
|
||||
self._args = None
|
||||
self._instance: UILocation | None = None
|
||||
self._controller = weakref.ref(controller)
|
||||
|
||||
def create(self) -> None:
|
||||
"""Create an instance of our UI."""
|
||||
cls = self._get_class()
|
||||
self._instance = cls()
|
||||
|
||||
def destroy(self) -> None:
|
||||
"""Transition out our UI if it exists."""
|
||||
if self._instance is None:
|
||||
return
|
||||
print('WOULD TRANSITION OUT', self._name)
|
||||
|
||||
def _get_class(self) -> Type[UILocation]:
|
||||
"""Returns the UI class our name points to."""
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
# TEMP HARD CODED - WILL REPLACE THIS WITH BA_META LOOKUPS.
|
||||
if self._name == 'mainmenu':
|
||||
# Shut pylint up.
|
||||
if bool(False):
|
||||
return UILocation
|
||||
raise RuntimeError('FIXME UNIMPLEMENTED')
|
||||
# from bauiv1lib import mainmenu
|
||||
# return cast(Type[UILocation], mainmenu.MainMenuWindow)
|
||||
|
||||
raise ValueError('unknown ui class ' + str(self._name))
|
||||
|
||||
|
||||
class UIController:
|
||||
"""Wrangles bauiv1.UILocations.
|
||||
|
||||
Category: User Interface Classes
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
# FIXME: document why we have separate stacks for game and menu...
|
||||
self._main_stack_game: list[UIEntry] = []
|
||||
self._main_stack_menu: list[UIEntry] = []
|
||||
|
||||
# This points at either the game or menu stack.
|
||||
self._main_stack: list[UIEntry] | None = None
|
||||
|
||||
# There's only one of these since we don't need to preserve its state
|
||||
# between sessions.
|
||||
self._dialog_stack: list[UIEntry] = []
|
||||
|
||||
def show_main_menu(self, in_game: bool = True) -> None:
|
||||
"""Show the main menu, clearing other UIs from location stacks."""
|
||||
self._main_stack = []
|
||||
self._dialog_stack = []
|
||||
self._main_stack = (
|
||||
self._main_stack_game if in_game else self._main_stack_menu
|
||||
)
|
||||
self._main_stack.append(UIEntry('mainmenu', self))
|
||||
self._update_ui()
|
||||
|
||||
def _update_ui(self) -> None:
|
||||
"""Instantiate the topmost ui in our stacks."""
|
||||
|
||||
# First tell any existing UIs to get outta here.
|
||||
for stack in (self._dialog_stack, self._main_stack):
|
||||
assert stack is not None
|
||||
for entry in stack:
|
||||
entry.destroy()
|
||||
|
||||
# Now create the topmost one if there is one.
|
||||
entrynew = (
|
||||
self._dialog_stack[-1]
|
||||
if self._dialog_stack
|
||||
else self._main_stack[-1] if self._main_stack else None
|
||||
)
|
||||
if entrynew is not None:
|
||||
entrynew.create()
|
||||
|
||||
|
||||
def uicleanupcheck(obj: Any, widget: bauiv1.Widget) -> None:
|
||||
"""Add a check to ensure a widget-owning object gets cleaned up properly.
|
||||
"""Checks to ensure a widget-owning object gets cleaned up properly.
|
||||
|
||||
Category: User Interface Functions
|
||||
|
||||
@ -233,8 +304,10 @@ def ui_upkeep() -> None:
|
||||
'WARNING:',
|
||||
obj,
|
||||
'is still alive 5 second after its widget died;'
|
||||
' you might have a memory leak. See efro.debug module'
|
||||
' for tools to help debug this.',
|
||||
' you might have a memory leak. Look for circular'
|
||||
' references or outside things referencing your window'
|
||||
' instance. See efro.debug module'
|
||||
' for tools that can help debug this sort of thing.',
|
||||
)
|
||||
else:
|
||||
remainingchecks.append(check)
|
||||
|
||||
@ -7,32 +7,15 @@ from __future__ import annotations
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
def show_sign_in_prompt(account_type: str | None = None) -> None:
|
||||
def show_sign_in_prompt() -> None:
|
||||
"""Bring up a prompt telling the user they must sign in."""
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
from bauiv1lib.account import settings
|
||||
from bauiv1lib.account.settings import AccountSettingsWindow
|
||||
|
||||
if account_type == 'Google Play':
|
||||
|
||||
def _do_sign_in() -> None:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
plus.sign_in_v1('Google Play')
|
||||
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource='notSignedInGooglePlayErrorText'),
|
||||
_do_sign_in,
|
||||
ok_text=bui.Lstr(resource='accountSettingsWindow.signInText'),
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
else:
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource='notSignedInErrorText'),
|
||||
lambda: settings.AccountSettingsWindow(
|
||||
modal=True, close_once_signed_in=True
|
||||
),
|
||||
ok_text=bui.Lstr(resource='accountSettingsWindow.signInText'),
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource='notSignedInErrorText'),
|
||||
lambda: AccountSettingsWindow(modal=True, close_once_signed_in=True),
|
||||
ok_text=bui.Lstr(resource='accountSettingsWindow.signInText'),
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
|
||||
import time
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
from bacommon.cloud import WebLocation
|
||||
from bacommon.login import LoginType
|
||||
@ -20,12 +21,12 @@ import bauiv1 as bui
|
||||
FORCE_ENABLE_V1_LINKING = False
|
||||
|
||||
|
||||
class AccountSettingsWindow(bui.Window):
|
||||
class AccountSettingsWindow(bui.MainWindow):
|
||||
"""Window for account related functionality."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
modal: bool = False,
|
||||
origin_widget: bui.Widget | None = None,
|
||||
close_once_signed_in: bool = False,
|
||||
@ -46,16 +47,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
|
||||
self._explicitly_signed_out_of_gpgs = False
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'accountSettingsWindow'
|
||||
self._modal = modal
|
||||
self._needs_refresh = False
|
||||
@ -71,10 +62,10 @@ class AccountSettingsWindow(bui.Window):
|
||||
assert app.classic is not None
|
||||
uiscale = app.ui_v1.uiscale
|
||||
|
||||
self._width = 860 if uiscale is bui.UIScale.SMALL else 660
|
||||
x_offs = 100 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._width = 850 if uiscale is bui.UIScale.SMALL else 660
|
||||
x_offs = 70 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
390
|
||||
380
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 430 if uiscale is bui.UIScale.MEDIUM else 490
|
||||
)
|
||||
@ -107,23 +98,28 @@ class AccountSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
# transition=transition,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.09
|
||||
2.07
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -19) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, 8) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL and app.ui_v1.use_toolbars:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = None
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
@ -137,7 +133,7 @@ class AccountSettingsWindow(bui.Window):
|
||||
resource='doneText' if self._modal else 'backText'
|
||||
),
|
||||
button_type='regular' if self._modal else 'back',
|
||||
on_activate_call=self._back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
if not self._modal:
|
||||
@ -148,12 +144,15 @@ class AccountSettingsWindow(bui.Window):
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
titleyoffs = -12 if uiscale is bui.UIScale.SMALL else 0
|
||||
titlescale = 0.6 if uiscale is bui.UIScale.SMALL else 1.0
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 41),
|
||||
position=(self._width * 0.5, self._height - 41 + titleyoffs),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource=f'{self._r}.titleText'),
|
||||
color=app.ui_v1.title_color,
|
||||
scale=titlescale,
|
||||
maxwidth=self._width - 340,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
@ -175,13 +174,27 @@ class AccountSettingsWindow(bui.Window):
|
||||
self._refresh()
|
||||
self._restore_state()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _update(self) -> None:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
# If they want us to close once we're signed in, do so.
|
||||
if self._close_once_signed_in and self._v1_signed_in:
|
||||
self._back()
|
||||
self.main_window_back()
|
||||
return
|
||||
|
||||
# Hmm should update this to use get_account_state_num.
|
||||
@ -215,7 +228,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib import confirm
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -316,10 +328,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
show_game_service_button = game_center_active
|
||||
game_service_button_space = 60.0
|
||||
|
||||
# Phasing this out.
|
||||
show_what_is_v2 = False
|
||||
# show_what_is_v2 = self._v1_signed_in and v1_account_type == 'V2'
|
||||
|
||||
# Phasing this out (for V2 accounts at least).
|
||||
show_linked_accounts_text = (
|
||||
self._v1_signed_in and v1_account_type != 'V2'
|
||||
@ -328,36 +336,41 @@ class AccountSettingsWindow(bui.Window):
|
||||
|
||||
# Always show achievements except in the game-center case where
|
||||
# its unified UI covers them.
|
||||
show_achievements_button = self._v1_signed_in and not game_center_active
|
||||
# show_achievements_button =
|
||||
# self._v1_signed_in and not game_center_active
|
||||
|
||||
# Update: No longer showing this since its visible on main
|
||||
# toolbar.
|
||||
show_achievements_button = False
|
||||
achievements_button_space = 60.0
|
||||
|
||||
show_achievements_text = (
|
||||
self._v1_signed_in and not show_achievements_button
|
||||
)
|
||||
# show_achievements_text = (
|
||||
# self._v1_signed_in and not show_achievements_button
|
||||
# )
|
||||
|
||||
# Update: No longer showing this since its visible on main
|
||||
# toolbar.
|
||||
show_achievements_text = False
|
||||
achievements_text_space = 27.0
|
||||
|
||||
show_leaderboards_button = self._v1_signed_in and gpgs_active
|
||||
leaderboards_button_space = 60.0
|
||||
|
||||
show_campaign_progress = self._v1_signed_in
|
||||
# Update: No longer showing this; trying to get progress type
|
||||
# stuff out of the account panel.
|
||||
# show_campaign_progress = self._v1_signed_in
|
||||
show_campaign_progress = False
|
||||
campaign_progress_space = 27.0
|
||||
|
||||
show_tickets = self._v1_signed_in
|
||||
# show_tickets = self._v1_signed_in
|
||||
show_tickets = False
|
||||
tickets_space = 27.0
|
||||
|
||||
show_reset_progress_button = False
|
||||
reset_progress_button_space = 70.0
|
||||
|
||||
show_manage_v2_account_button = primary_v2_account is not None
|
||||
manage_v2_account_button_space = 100.0
|
||||
show_manage_account_button = primary_v2_account is not None
|
||||
manage_account_button_space = 70.0
|
||||
|
||||
show_delete_account_button = primary_v2_account is not None
|
||||
delete_account_button_space = 80.0
|
||||
|
||||
show_player_profiles_button = self._v1_signed_in
|
||||
player_profiles_button_space = (
|
||||
70.0 if show_manage_v2_account_button else 100.0
|
||||
)
|
||||
delete_account_button_space = 70.0
|
||||
|
||||
show_link_accounts_button = self._v1_signed_in and (
|
||||
primary_v2_account is None or FORCE_ENABLE_V1_LINKING
|
||||
@ -376,7 +389,7 @@ class AccountSettingsWindow(bui.Window):
|
||||
show_sign_out_button = primary_v2_account is not None or (
|
||||
self._v1_signed_in and v1_account_type == 'Local'
|
||||
)
|
||||
sign_out_button_space = 80.0
|
||||
sign_out_button_space = 70.0
|
||||
|
||||
# We can show cancel if we're either waiting on an adapter to
|
||||
# provide us with v2 credentials or waiting for those
|
||||
@ -419,12 +432,8 @@ class AccountSettingsWindow(bui.Window):
|
||||
self._sub_height += tickets_space
|
||||
if show_sign_in_benefits:
|
||||
self._sub_height += sign_in_benefits_space
|
||||
if show_reset_progress_button:
|
||||
self._sub_height += reset_progress_button_space
|
||||
if show_manage_v2_account_button:
|
||||
self._sub_height += manage_v2_account_button_space
|
||||
if show_player_profiles_button:
|
||||
self._sub_height += player_profiles_button_space
|
||||
if show_manage_account_button:
|
||||
self._sub_height += manage_account_button_space
|
||||
if show_link_accounts_button:
|
||||
self._sub_height += link_accounts_button_space
|
||||
if show_unlink_accounts_button:
|
||||
@ -452,8 +461,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
v = self._sub_height - 10.0
|
||||
|
||||
assert bui.app.classic is not None
|
||||
self._account_name_what_is_text: bui.Widget | None
|
||||
self._account_name_what_is_y = 0.0
|
||||
self._account_name_text: bui.Widget | None
|
||||
if show_signed_in_as:
|
||||
v -= signed_in_as_space * 0.2
|
||||
@ -485,32 +492,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if show_what_is_v2:
|
||||
self._account_name_what_is_y = v - 23.0
|
||||
self._account_name_what_is_text = bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(0.0, self._account_name_what_is_y),
|
||||
size=(220.0, 60),
|
||||
text=bui.Lstr(
|
||||
value='${WHAT} -->',
|
||||
subs=[('${WHAT}', bui.Lstr(resource='whatIsThisText'))],
|
||||
),
|
||||
scale=0.6,
|
||||
color=(0.3, 0.7, 0.05),
|
||||
maxwidth=130.0,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
autoselect=True,
|
||||
selectable=True,
|
||||
on_activate_call=show_what_is_v2_page,
|
||||
click_activate=True,
|
||||
glow_type='uniform',
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = self._account_name_what_is_text
|
||||
else:
|
||||
self._account_name_what_is_text = None
|
||||
|
||||
self._refresh_account_name_text()
|
||||
|
||||
v -= signed_in_as_space * 0.4
|
||||
@ -565,7 +546,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
|
||||
else:
|
||||
self._account_name_text = None
|
||||
self._account_name_what_is_text = None
|
||||
|
||||
if self._back_button is None:
|
||||
bbtn = bui.get_special_widget('back_button')
|
||||
@ -641,11 +621,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
bui.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
@ -683,11 +661,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
bui.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
@ -752,11 +728,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
bui.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
@ -821,21 +795,19 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
bui.widget(edit=btn, show_buffer_bottom=40, show_buffer_top=100)
|
||||
self._sign_in_text = None
|
||||
|
||||
if show_manage_v2_account_button:
|
||||
if show_manage_account_button:
|
||||
button_width = 300
|
||||
v -= manage_v2_account_button_space
|
||||
self._manage_v2_button = btn = bui.buttonwidget(
|
||||
v -= manage_account_button_space
|
||||
self._manage_button = btn = bui.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=((self._sub_width - button_width) * 0.5, v + 30),
|
||||
position=((self._sub_width - button_width) * 0.5, v),
|
||||
autoselect=True,
|
||||
size=(button_width, 60),
|
||||
label=bui.Lstr(resource=f'{self._r}.manageAccountText'),
|
||||
@ -846,35 +818,10 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
|
||||
if show_player_profiles_button:
|
||||
button_width = 300
|
||||
v -= player_profiles_button_space
|
||||
self._player_profiles_button = btn = bui.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=((self._sub_width - button_width) * 0.5, v + 30),
|
||||
autoselect=True,
|
||||
size=(button_width, 60),
|
||||
label=bui.Lstr(resource='playerProfilesWindow.titleText'),
|
||||
color=(0.55, 0.5, 0.6),
|
||||
icon=bui.gettexture('cuteSpaz'),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
on_activate_call=self._player_profiles_press,
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=0)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
|
||||
# the button to go to OS-Specific leaderboards/high-score-lists/etc.
|
||||
if show_game_service_button:
|
||||
@ -904,11 +851,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
v -= game_service_button_space * 0.4
|
||||
else:
|
||||
@ -959,11 +904,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
v -= achievements_button_space * 0.15
|
||||
else:
|
||||
@ -990,11 +933,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
v -= leaderboards_button_space * 0.15
|
||||
else:
|
||||
@ -1039,41 +980,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
self._tickets_text = None
|
||||
|
||||
# bit of spacing before the reset/sign-out section
|
||||
v -= 5
|
||||
# v -= 5
|
||||
|
||||
button_width = 250
|
||||
if show_reset_progress_button:
|
||||
confirm_text = (
|
||||
bui.Lstr(resource=f'{self._r}.resetProgressConfirmText')
|
||||
if self._can_reset_achievements
|
||||
else bui.Lstr(
|
||||
resource=f'{self._r}.resetProgressConfirmNoAchievementsText'
|
||||
)
|
||||
)
|
||||
v -= reset_progress_button_space
|
||||
self._reset_progress_button = btn = bui.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
position=((self._sub_width - button_width) * 0.5, v),
|
||||
color=(0.55, 0.5, 0.6),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
autoselect=True,
|
||||
size=(button_width, 60),
|
||||
label=bui.Lstr(resource=f'{self._r}.resetProgressText'),
|
||||
on_activate_call=lambda: confirm.ConfirmWindow(
|
||||
text=confirm_text,
|
||||
width=500,
|
||||
height=200,
|
||||
action=self._reset_progress,
|
||||
),
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn)
|
||||
|
||||
self._linked_accounts_text: bui.Widget | None
|
||||
if show_linked_accounts_text:
|
||||
@ -1133,11 +1042,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=50)
|
||||
|
||||
self._unlink_accounts_button: bui.Widget | None
|
||||
@ -1165,11 +1072,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=50)
|
||||
self._update_unlink_accounts_button()
|
||||
else:
|
||||
@ -1235,11 +1140,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15)
|
||||
|
||||
if show_cancel_sign_in_button:
|
||||
@ -1256,11 +1159,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15)
|
||||
|
||||
if show_delete_account_button:
|
||||
@ -1277,11 +1178,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
)
|
||||
if first_selectable is None:
|
||||
first_selectable = btn
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn, right_widget=bui.get_special_widget('squad_button')
|
||||
)
|
||||
bui.widget(edit=btn, left_widget=bbtn, show_buffer_bottom=15)
|
||||
|
||||
# Whatever the topmost selectable thing is, we want it to scroll all
|
||||
@ -1322,9 +1221,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
position=self._achievements_button.get_screen_space_center()
|
||||
)
|
||||
|
||||
def _on_what_is_v2_press(self) -> None:
|
||||
show_what_is_v2_page()
|
||||
|
||||
def _on_manage_account_press(self) -> None:
|
||||
self._do_manage_account_press(WebLocation.ACCOUNT_EDITOR)
|
||||
|
||||
@ -1502,16 +1398,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
name_str = '??'
|
||||
|
||||
bui.textwidget(edit=self._account_name_text, text=name_str)
|
||||
if self._account_name_what_is_text is not None:
|
||||
swidth = bui.get_string_width(name_str, suppress_warning=True)
|
||||
# Eww; number-fudging. Need to recalibrate this if
|
||||
# account name scaling changes.
|
||||
x = self._sub_width * 0.5 - swidth * 0.75 - 190
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._account_name_what_is_text,
|
||||
position=(x, self._account_name_what_is_y),
|
||||
)
|
||||
|
||||
def _refresh_achievements(self) -> None:
|
||||
assert bui.app.classic is not None
|
||||
@ -1550,23 +1436,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
|
||||
AccountUnlinkWindow(origin_widget=self._unlink_accounts_button)
|
||||
|
||||
def _player_profiles_press(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ProfileBrowserWindow(
|
||||
origin_widget=self._player_profiles_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _cancel_sign_in_press(self) -> None:
|
||||
# If we're waiting on an adapter to give us credentials, abort.
|
||||
self._signing_in_adapter = None
|
||||
@ -1674,14 +1543,14 @@ class AccountSettingsWindow(bui.Window):
|
||||
bui.getsound('error').play()
|
||||
else:
|
||||
# Success! Plug in these credentials which will begin
|
||||
# verifying them and set our primary account-handle
|
||||
# when finished.
|
||||
# verifying them and set our primary account-handle when
|
||||
# finished.
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
plus.accounts.set_primary_credentials(result.credentials)
|
||||
|
||||
# Special case - if the user has explicitly logged out and
|
||||
# logged in again with GPGS via this button, warn them that
|
||||
# Special case - if the user has explicitly signed out and
|
||||
# signed in again with GPGS via this button, warn them that
|
||||
# they need to use the app if they want to switch to a
|
||||
# different GPGS account.
|
||||
if (
|
||||
@ -1709,9 +1578,9 @@ class AccountSettingsWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.connectivity import wait_for_connectivity
|
||||
|
||||
# If we're still waiting for our master-server connection,
|
||||
# keep the user informed of this instead of rushing in and
|
||||
# failing immediately.
|
||||
# If we're still waiting for our master-server connection, keep
|
||||
# the user informed of this instead of rushing in and failing
|
||||
# immediately.
|
||||
wait_for_connectivity(on_connected=self._v2_proxy_sign_in)
|
||||
|
||||
def _v2_proxy_sign_in(self) -> None:
|
||||
@ -1721,44 +1590,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
assert self._sign_in_v2_proxy_button is not None
|
||||
V2ProxySignInWindow(origin_widget=self._sign_in_v2_proxy_button)
|
||||
|
||||
def _reset_progress(self) -> None:
|
||||
try:
|
||||
assert bui.app.classic is not None
|
||||
# FIXME: This would need to happen server-side these days.
|
||||
if self._can_reset_achievements:
|
||||
logging.warning('ach resets not wired up.')
|
||||
# bui.app.config['Achievements'] = {}
|
||||
# bui.reset_achievements()
|
||||
campaign = bui.app.classic.getcampaign('Default')
|
||||
campaign.reset() # also writes the config..
|
||||
campaign = bui.app.classic.getcampaign('Challenges')
|
||||
campaign.reset() # also writes the config..
|
||||
except Exception:
|
||||
logging.exception('Error resetting co-op campaign progress.')
|
||||
|
||||
bui.getsound('shieldDown').play()
|
||||
self._refresh()
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
try:
|
||||
sel = self._root_widget.get_selected_child()
|
||||
@ -1788,15 +1619,6 @@ class AccountSettingsWindow(bui.Window):
|
||||
logging.exception('Error restoring state for %s.', self)
|
||||
|
||||
|
||||
def show_what_is_v2_page() -> None:
|
||||
"""Show the webpage describing V2 accounts."""
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
bamasteraddr = plus.get_master_server_address(version=2)
|
||||
bui.open_url(f'{bamasteraddr}/whatisv2')
|
||||
|
||||
|
||||
def show_what_is_legacy_unlinking_page() -> None:
|
||||
"""Show the webpage describing legacy unlinking."""
|
||||
plus = bui.app.plus
|
||||
|
||||
@ -40,6 +40,7 @@ class AchievementsWindow(PopupWindow):
|
||||
size=(self._width, self._height),
|
||||
scale=scale,
|
||||
bg_color=bg_color,
|
||||
edge_buffer_scale=4.0, # Try to keep button unobscured.
|
||||
)
|
||||
|
||||
self._cancel_button = bui.buttonwidget(
|
||||
@ -74,7 +75,7 @@ class AchievementsWindow(PopupWindow):
|
||||
scale=0.6,
|
||||
text=txt_final,
|
||||
maxwidth=200,
|
||||
color=(1, 1, 1, 0.4),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
)
|
||||
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
|
||||
@ -29,7 +29,7 @@ class ShowFriendCodeWindow(bui.Window):
|
||||
color=(0.45, 0.63, 0.15),
|
||||
transition='in_scale',
|
||||
scale=(
|
||||
1.7
|
||||
1.5
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
|
||||
@ -5,25 +5,27 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import cast
|
||||
from typing import cast, override
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class DebugWindow(bui.Window):
|
||||
"""Window for debugging internal values."""
|
||||
class BenchmarksAndStressTestsWindow(bui.MainWindow):
|
||||
"""Window for launching benchmarks or stress tests."""
|
||||
|
||||
def __init__(self, transition: str | None = 'in_right'):
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib import popup
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_location('Benchmarks & Stress Tests')
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = width = 580
|
||||
self._width = width = 650 if uiscale is bui.UIScale.SMALL else 580
|
||||
self._height = height = (
|
||||
350
|
||||
330
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 420 if uiscale is bui.UIScale.MEDIUM else 520
|
||||
)
|
||||
@ -44,28 +46,41 @@ class DebugWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
scale=(
|
||||
2.35
|
||||
2.32
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.55 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -30) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._done_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40, height - 67),
|
||||
size=(120, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='doneText'),
|
||||
on_activate_call=self._done,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
if bui.app.ui_v1.uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._done_button = bui.get_special_widget('back_button')
|
||||
else:
|
||||
self._done_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40, height - 67),
|
||||
size=(120, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='doneText'),
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, height - 60),
|
||||
@ -303,6 +318,16 @@ class DebugWindow(bui.Window):
|
||||
)
|
||||
bui.widget(btn, show_buffer_bottom=50)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def _stress_test_player_count_decrement(self) -> None:
|
||||
self._stress_test_player_count = max(
|
||||
1, self._stress_test_player_count - 1
|
||||
@ -370,18 +395,3 @@ class DebugWindow(bui.Window):
|
||||
round_duration=self._stress_test_round_duration,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
|
||||
def _done(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
@ -61,7 +61,7 @@ class ConfirmWindow:
|
||||
toolbar_visibility='menu_minimal_no_back',
|
||||
parent=bui.get_special_widget('overlay_stack'),
|
||||
scale=(
|
||||
2.1
|
||||
1.9
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
|
||||
@ -38,7 +38,7 @@ class ContinuesWindow(bui.Window):
|
||||
bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
background=False,
|
||||
toolbar_visibility='menu_currency',
|
||||
toolbar_visibility='menu_store',
|
||||
transition='in_scale',
|
||||
scale=1.5,
|
||||
)
|
||||
@ -100,29 +100,8 @@ class ContinuesWindow(bui.Window):
|
||||
|
||||
self._tickets_text_base: str | None
|
||||
self._tickets_text: bui.Widget | None
|
||||
if not bui.app.ui_v1.use_toolbars:
|
||||
self._tickets_text_base = bui.Lstr(
|
||||
resource='getTicketsWindow.youHaveShortText',
|
||||
fallback_resource='getTicketsWindow.youHaveText',
|
||||
).evaluate()
|
||||
self._tickets_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text='',
|
||||
flatness=1.0,
|
||||
color=(0.2, 1.0, 0.2),
|
||||
shadow=1.0,
|
||||
position=(
|
||||
self._width * 0.5 + width_total_half,
|
||||
self._height - 50,
|
||||
),
|
||||
size=(0, 0),
|
||||
scale=0.35,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
)
|
||||
else:
|
||||
self._tickets_text_base = None
|
||||
self._tickets_text = None
|
||||
self._tickets_text_base = None
|
||||
self._tickets_text = None
|
||||
|
||||
self._counter_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -214,7 +193,7 @@ class ContinuesWindow(bui.Window):
|
||||
self._on_cancel()
|
||||
|
||||
def _on_continue_press(self) -> None:
|
||||
from bauiv1lib import gettickets
|
||||
# from bauiv1lib import gettickets
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -238,7 +217,7 @@ class ContinuesWindow(bui.Window):
|
||||
self._counting_down = False
|
||||
bui.textwidget(edit=self._counter_text, text='')
|
||||
bui.getsound('error').play()
|
||||
gettickets.show_get_tickets_prompt()
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
return
|
||||
if not self._transitioning_out:
|
||||
bui.getsound('swish').play()
|
||||
|
||||
@ -7,12 +7,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from threading import Thread
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from bauiv1lib.store.button import StoreButton
|
||||
from bauiv1lib.league.rankbutton import LeagueRankButton
|
||||
from bauiv1lib.store.browser import StoreBrowserWindow
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@ -21,7 +17,7 @@ if TYPE_CHECKING:
|
||||
from bauiv1lib.coop.tournamentbutton import TournamentButton
|
||||
|
||||
|
||||
class CoopBrowserWindow(bui.Window):
|
||||
class CoopBrowserWindow(bui.MainWindow):
|
||||
"""Window for browsing co-op levels/games/etc."""
|
||||
|
||||
def __init__(
|
||||
@ -37,16 +33,18 @@ class CoopBrowserWindow(bui.Window):
|
||||
|
||||
# Preload some modules we use in a background thread so we won't
|
||||
# have a visual hitch when the user taps them.
|
||||
Thread(target=self._preload_modules).start()
|
||||
bui.app.threadpool_submit_no_wait(self._preload_modules)
|
||||
|
||||
bui.set_analytics_screen('Coop Window')
|
||||
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
classic = app.classic
|
||||
assert classic is not None
|
||||
cfg = app.config
|
||||
|
||||
# Quick note to players that tourneys won't work in ballistica
|
||||
# core builds. (need to split the word so it won't get subbed out)
|
||||
# core builds. (need to split the word so it won't get subbed
|
||||
# out)
|
||||
if 'ballistica' + 'kit' == bui.appname():
|
||||
bui.apptimer(
|
||||
1.0,
|
||||
@ -56,16 +54,6 @@ class CoopBrowserWindow(bui.Window):
|
||||
),
|
||||
)
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
# Try to recreate the same number of buttons we had last time so our
|
||||
# re-selection code works.
|
||||
self._tournament_button_count = app.config.get('Tournament Rows', 0)
|
||||
@ -83,16 +71,14 @@ class CoopBrowserWindow(bui.Window):
|
||||
self._hard_button_lock_image: bui.Widget | None = None
|
||||
self._campaign_percent_text: bui.Widget | None = None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
uiscale = app.ui_v1.uiscale
|
||||
self._width = 1520 if uiscale is bui.UIScale.SMALL else 1120
|
||||
self._x_inset = x_inset = 200 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
657
|
||||
565
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 730 if uiscale is bui.UIScale.MEDIUM else 800
|
||||
)
|
||||
app.ui_v1.set_main_menu_location('Coop Select')
|
||||
self._r = 'coopSelectWindow'
|
||||
top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
@ -104,7 +90,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
|
||||
if (
|
||||
self._campaign_difficulty == 'hard'
|
||||
and not app.classic.accounts.have_pro_options()
|
||||
and not classic.accounts.have_pro_options()
|
||||
):
|
||||
plus.add_v1_account_transaction(
|
||||
{
|
||||
@ -119,99 +105,114 @@ class CoopBrowserWindow(bui.Window):
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
toolbar_visibility='menu_full',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
stack_offset=(
|
||||
(0, -15)
|
||||
(0, -17)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (0, 0) if uiscale is bui.UIScale.MEDIUM else (0, 0)
|
||||
),
|
||||
transition=transition,
|
||||
scale=(
|
||||
1.2
|
||||
1.28
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 0.8 if uiscale is bui.UIScale.MEDIUM else 0.75
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = None
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
75 + x_inset,
|
||||
self._height
|
||||
- 87
|
||||
- (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
),
|
||||
position=(75 + x_inset, self._height - 87),
|
||||
size=(120, 60),
|
||||
scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
|
||||
self._league_rank_button: LeagueRankButton | None
|
||||
self._store_button: StoreButton | None
|
||||
self._store_button_widget: bui.Widget | None
|
||||
self._league_rank_button_widget: bui.Widget | None
|
||||
|
||||
if not app.ui_v1.use_toolbars:
|
||||
prb = self._league_rank_button = LeagueRankButton(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width - (282 + x_inset),
|
||||
self._height
|
||||
- 85
|
||||
- (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
),
|
||||
size=(100, 60),
|
||||
color=(0.4, 0.4, 0.9),
|
||||
textcolor=(0.9, 0.9, 2.0),
|
||||
scale=1.05,
|
||||
on_activate_call=bui.WeakCall(self._switch_to_league_rankings),
|
||||
)
|
||||
self._league_rank_button_widget = prb.get_button()
|
||||
|
||||
sbtn = self._store_button = StoreButton(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
self._width - (170 + x_inset),
|
||||
self._height
|
||||
- 85
|
||||
- (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
),
|
||||
size=(100, 60),
|
||||
color=(0.6, 0.4, 0.7),
|
||||
show_tickets=True,
|
||||
button_type='square',
|
||||
sale_scale=0.85,
|
||||
textcolor=(0.9, 0.7, 1.0),
|
||||
scale=1.05,
|
||||
on_activate_call=bui.WeakCall(self._switch_to_score, None),
|
||||
)
|
||||
self._store_button_widget = sbtn.get_button()
|
||||
bui.widget(
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
right_widget=self._league_rank_button_widget,
|
||||
button_type='backSmall',
|
||||
size=(60, 50),
|
||||
position=(
|
||||
75 + x_inset,
|
||||
self._height - 87 + 6,
|
||||
),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._league_rank_button_widget,
|
||||
left_widget=self._back_button,
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
else:
|
||||
self._league_rank_button = None
|
||||
self._store_button = None
|
||||
self._store_button_widget = None
|
||||
self._league_rank_button_widget = None
|
||||
|
||||
# self._league_rank_button: LeagueRankButton | None
|
||||
# self._store_button: StoreButton | None
|
||||
# self._store_button_widget: bui.Widget | None
|
||||
# self._league_rank_button_widget: bui.Widget | None
|
||||
|
||||
# if not app.ui_v1.use_toolbars:
|
||||
# prb = self._league_rank_button = LeagueRankButton(
|
||||
# parent=self._root_widget,
|
||||
# position=(
|
||||
# self._width - (282 + x_inset),
|
||||
# self._height
|
||||
# - 85
|
||||
# - (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
# ),
|
||||
# size=(100, 60),
|
||||
# color=(0.4, 0.4, 0.9),
|
||||
# textcolor=(0.9, 0.9, 2.0),
|
||||
# scale=1.05,
|
||||
# on_activate_call=bui.WeakCall(
|
||||
# self._switch_to_league_rankings),
|
||||
# )
|
||||
# self._league_rank_button_widget = prb.get_button()
|
||||
|
||||
# sbtn = self._store_button = StoreButton(
|
||||
# parent=self._root_widget,
|
||||
# position=(
|
||||
# self._width - (170 + x_inset),
|
||||
# self._height
|
||||
# - 85
|
||||
# - (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
# ),
|
||||
# size=(100, 60),
|
||||
# color=(0.6, 0.4, 0.7),
|
||||
# show_tickets=True,
|
||||
# button_type='square',
|
||||
# sale_scale=0.85,
|
||||
# textcolor=(0.9, 0.7, 1.0),
|
||||
# scale=1.05,
|
||||
# on_activate_call=bui.WeakCall(self._switch_to_score, None),
|
||||
# )
|
||||
# self._store_button_widget = sbtn.get_button()
|
||||
# assert self._back_button is not None
|
||||
# bui.widget(
|
||||
# edit=self._back_button,
|
||||
# right_widget=self._league_rank_button_widget,
|
||||
# )
|
||||
# bui.widget(
|
||||
# edit=self._league_rank_button_widget,
|
||||
# left_widget=self._back_button,
|
||||
# )
|
||||
# else:
|
||||
# self._league_rank_button = None
|
||||
# self._store_button = None
|
||||
# self._store_button_widget = None
|
||||
# self._league_rank_button_widget = None
|
||||
|
||||
# Move our corner buttons dynamically to keep them out of the way of
|
||||
# the party icon :-(
|
||||
self._update_corner_button_positions()
|
||||
self._update_corner_button_positions_timer = bui.AppTimer(
|
||||
1.0, bui.WeakCall(self._update_corner_button_positions), repeat=True
|
||||
)
|
||||
# self._update_corner_button_positions()
|
||||
# self._update_corner_button_positions_timer = bui.AppTimer(
|
||||
# 1.0, bui.WeakCall(
|
||||
# self._update_corner_button_positions), repeat=True
|
||||
# )
|
||||
|
||||
self._last_tournament_query_time: float | None = None
|
||||
self._last_tournament_query_response_time: float | None = None
|
||||
@ -245,31 +246,14 @@ class CoopBrowserWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.textwidget(edit=txt, text='')
|
||||
|
||||
if self._back_button is not None:
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
button_type='backSmall',
|
||||
size=(60, 50),
|
||||
position=(
|
||||
75 + x_inset,
|
||||
self._height
|
||||
- 87
|
||||
- (4 if uiscale is bui.UIScale.SMALL else 0)
|
||||
+ 6,
|
||||
),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
self._selected_row = cfg.get('Selected Coop Row', None)
|
||||
|
||||
self._scroll_width = self._width - (130 + 2 * x_inset)
|
||||
self._scroll_height = self._height - (
|
||||
190
|
||||
if uiscale is bui.UIScale.SMALL and app.ui_v1.use_toolbars
|
||||
else 160
|
||||
185 if uiscale is bui.UIScale.SMALL else 160
|
||||
)
|
||||
|
||||
self._subcontainerwidth = 800.0
|
||||
@ -280,7 +264,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
highlight=False,
|
||||
position=(
|
||||
(65 + x_inset, 120)
|
||||
if uiscale is bui.UIScale.SMALL and app.ui_v1.use_toolbars
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (65 + x_inset, 70)
|
||||
),
|
||||
size=(self._scroll_width, self._scroll_height),
|
||||
@ -309,17 +293,17 @@ class CoopBrowserWindow(bui.Window):
|
||||
# each one of those tournaments, go ahead and display it as a
|
||||
# starting point.
|
||||
if (
|
||||
app.classic.accounts.account_tournament_list is not None
|
||||
and app.classic.accounts.account_tournament_list[0]
|
||||
classic.accounts.account_tournament_list is not None
|
||||
and classic.accounts.account_tournament_list[0]
|
||||
== plus.get_v1_account_state_num()
|
||||
and all(
|
||||
t_id in app.classic.accounts.tournament_info
|
||||
for t_id in app.classic.accounts.account_tournament_list[1]
|
||||
t_id in classic.accounts.tournament_info
|
||||
for t_id in classic.accounts.account_tournament_list[1]
|
||||
)
|
||||
):
|
||||
tourney_data = [
|
||||
app.classic.accounts.tournament_info[t_id]
|
||||
for t_id in app.classic.accounts.account_tournament_list[1]
|
||||
classic.accounts.tournament_info[t_id]
|
||||
for t_id in classic.accounts.account_tournament_list[1]
|
||||
]
|
||||
self._update_for_data(tourney_data)
|
||||
|
||||
@ -329,37 +313,24 @@ class CoopBrowserWindow(bui.Window):
|
||||
)
|
||||
self._update()
|
||||
|
||||
def _update_corner_button_positions(self) -> None:
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
offs = (
|
||||
-55
|
||||
if uiscale is bui.UIScale.SMALL and bui.is_party_icon_visible()
|
||||
else 0
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
if self._league_rank_button is not None:
|
||||
self._league_rank_button.set_position(
|
||||
(
|
||||
self._width - 282 + offs - self._x_inset,
|
||||
self._height
|
||||
- 85
|
||||
- (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
)
|
||||
)
|
||||
if self._store_button is not None:
|
||||
self._store_button.set_position(
|
||||
(
|
||||
self._width - 170 + offs - self._x_inset,
|
||||
self._height
|
||||
- 85
|
||||
- (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
)
|
||||
)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
# pylint: disable=cyclic-import
|
||||
import bauiv1lib.purchase as _unused1
|
||||
import bauiv1lib.coop.gamebutton as _unused2
|
||||
import bauiv1lib.confirm as _unused3
|
||||
@ -382,9 +353,9 @@ class CoopBrowserWindow(bui.Window):
|
||||
|
||||
cur_time = bui.apptime()
|
||||
|
||||
# If its been a while since we got a tournament update, consider the
|
||||
# data invalid (prevents us from joining tournaments if our internet
|
||||
# connection goes down for a while).
|
||||
# If its been a while since we got a tournament update, consider
|
||||
# the data invalid (prevents us from joining tournaments if our
|
||||
# internet connection goes down for a while).
|
||||
if (
|
||||
self._last_tournament_query_response_time is None
|
||||
or bui.apptime() - self._last_tournament_query_response_time
|
||||
@ -466,8 +437,8 @@ class CoopBrowserWindow(bui.Window):
|
||||
logging.exception('Error updating campaign lock.')
|
||||
|
||||
def _update_for_data(self, data: list[dict[str, Any]] | None) -> None:
|
||||
# If the number of tournaments or challenges in the data differs from
|
||||
# our current arrangement, refresh with the new number.
|
||||
# If the number of tournaments or challenges in the data differs
|
||||
# from our current arrangement, refresh with the new number.
|
||||
if (data is None and self._tournament_button_count != 0) or (
|
||||
data is not None and (len(data) != self._tournament_button_count)
|
||||
):
|
||||
@ -541,6 +512,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
|
||||
def _refresh_campaign_row(self) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.coop.gamebutton import GameButton
|
||||
|
||||
@ -660,14 +632,21 @@ class CoopBrowserWindow(bui.Window):
|
||||
|
||||
bui.widget(edit=campaign_buttons[0], left_widget=self._easy_button)
|
||||
|
||||
if self._back_button is not None:
|
||||
bui.widget(edit=self._easy_button, up_widget=self._back_button)
|
||||
for btn in campaign_buttons:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
up_widget=self._back_button,
|
||||
down_widget=next_widget_down,
|
||||
)
|
||||
# bui.widget(edit=self._easy_button)
|
||||
# if self._back_button is not None:
|
||||
bui.widget(
|
||||
edit=self._easy_button,
|
||||
left_widget=self._back_button,
|
||||
up_widget=self._back_button,
|
||||
)
|
||||
bui.widget(edit=self._hard_button, left_widget=self._back_button)
|
||||
for btn in campaign_buttons:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
up_widget=self._back_button,
|
||||
)
|
||||
for btn in campaign_buttons:
|
||||
bui.widget(edit=btn, down_widget=next_widget_down)
|
||||
|
||||
# Update our existing percent-complete text.
|
||||
assert bui.app.classic is not None
|
||||
@ -721,7 +700,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
|
||||
tourney_row_height = 200
|
||||
self._subcontainerheight = (
|
||||
620 + self._tournament_button_count * tourney_row_height
|
||||
700 + self._tournament_button_count * tourney_row_height
|
||||
)
|
||||
|
||||
self._subcontainer = bui.containerwidget(
|
||||
@ -736,15 +715,11 @@ class CoopBrowserWindow(bui.Window):
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._scrollwidget
|
||||
)
|
||||
if self._back_button is not None:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
|
||||
w_parent = self._subcontainer
|
||||
h_base = 6
|
||||
|
||||
v = self._subcontainerheight - 73
|
||||
v = self._subcontainerheight - 90
|
||||
|
||||
self._campaign_percent_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
@ -757,7 +732,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
scale=1.1,
|
||||
)
|
||||
|
||||
row_v_show_buffer = 100
|
||||
row_v_show_buffer = 80
|
||||
v -= 198
|
||||
|
||||
h_scroll = bui.hscrollwidget(
|
||||
@ -817,17 +792,17 @@ class CoopBrowserWindow(bui.Window):
|
||||
textcolor=(0.7, 0.6, 0.75),
|
||||
autoselect=True,
|
||||
up_widget=self._campaign_h_scroll,
|
||||
left_widget=self._back_button,
|
||||
on_activate_call=self._on_tournament_info_press,
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._tournament_info_button,
|
||||
left_widget=self._tournament_info_button,
|
||||
right_widget=self._tournament_info_button,
|
||||
)
|
||||
|
||||
# Say 'unavailable' if there are zero tournaments, and if we're not
|
||||
# signed in add that as well (that's probably why we see
|
||||
# no tournaments).
|
||||
# Say 'unavailable' if there are zero tournaments, and if we're
|
||||
# not signed in add that as well (that's probably why we see no
|
||||
# tournaments).
|
||||
if self._tournament_button_count == 0:
|
||||
unavailable_text = bui.Lstr(resource='unavailableText')
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
@ -989,6 +964,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
if i + 1 < len(self._tournament_buttons)
|
||||
else custom_h_scroll
|
||||
),
|
||||
left_widget=self._back_button,
|
||||
)
|
||||
bui.widget(
|
||||
edit=tbutton.more_scores_button,
|
||||
@ -1007,7 +983,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
),
|
||||
)
|
||||
|
||||
for btn in self._custom_buttons:
|
||||
for i, btn in enumerate(self._custom_buttons):
|
||||
try:
|
||||
bui.widget(
|
||||
edit=btn.get_button(),
|
||||
@ -1017,18 +993,14 @@ class CoopBrowserWindow(bui.Window):
|
||||
else self._tournament_info_button
|
||||
),
|
||||
)
|
||||
if i == 0:
|
||||
bui.widget(
|
||||
edit=btn.get_button(), left_widget=self._back_button
|
||||
)
|
||||
|
||||
except Exception:
|
||||
logging.exception('Error wiring up custom buttons.')
|
||||
|
||||
if self._back_button is not None:
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button, on_activate_call=self._back
|
||||
)
|
||||
else:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
)
|
||||
|
||||
# There's probably several 'onSelected' callbacks pushed onto the
|
||||
# event queue.. we need to push ours too so we're enabled *after* them.
|
||||
bui.pushcall(self._enable_selectable_callback)
|
||||
@ -1041,63 +1013,63 @@ class CoopBrowserWindow(bui.Window):
|
||||
def _enable_selectable_callback(self) -> None:
|
||||
self._do_selection_callbacks = True
|
||||
|
||||
def _switch_to_league_rankings(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.account import show_sign_in_prompt
|
||||
from bauiv1lib.league.rankwindow import LeagueRankWindow
|
||||
# def _switch_to_league_rankings(self) -> None:
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.account import show_sign_in_prompt
|
||||
# from bauiv1lib.league.rankwindow import LeagueRankWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
# plus = bui.app.plus
|
||||
# assert plus is not None
|
||||
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert self._league_rank_button is not None
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
LeagueRankWindow(
|
||||
origin_widget=self._league_rank_button.get_button()
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# if plus.get_v1_account_state() != 'signed_in':
|
||||
# show_sign_in_prompt()
|
||||
# return
|
||||
# self._save_state()
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
# assert self._league_rank_button is not None
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# LeagueRankWindow(
|
||||
# origin_widget=self._league_rank_button.get_button()
|
||||
# ),
|
||||
# from_window=self,
|
||||
# )
|
||||
|
||||
def _switch_to_score(
|
||||
self,
|
||||
show_tab: (
|
||||
StoreBrowserWindow.TabID | None
|
||||
) = StoreBrowserWindow.TabID.EXTRAS,
|
||||
) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.account import show_sign_in_prompt
|
||||
# def _switch_to_score(
|
||||
# self,
|
||||
# show_tab: (
|
||||
# StoreBrowserWindow.TabID | None
|
||||
# ) = StoreBrowserWindow.TabID.EXTRAS,
|
||||
# ) -> None:
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.account import show_sign_in_prompt
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
# plus = bui.app.plus
|
||||
# assert plus is not None
|
||||
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
show_sign_in_prompt()
|
||||
return
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert self._store_button is not None
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
StoreBrowserWindow(
|
||||
origin_widget=self._store_button.get_button(),
|
||||
show_tab=show_tab,
|
||||
back_location='CoopBrowserWindow',
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# if plus.get_v1_account_state() != 'signed_in':
|
||||
# show_sign_in_prompt()
|
||||
# return
|
||||
# self._save_state()
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
# assert self._store_button is not None
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# StoreBrowserWindow(
|
||||
# origin_widget=self._store_button.get_button(),
|
||||
# show_tab=show_tab,
|
||||
# back_location='CoopBrowserWindow',
|
||||
# ),
|
||||
# from_window=self,
|
||||
# )
|
||||
|
||||
def is_tourney_data_up_to_date(self) -> bool:
|
||||
"""Return whether our tourney data is up to date."""
|
||||
@ -1252,24 +1224,23 @@ class CoopBrowserWindow(bui.Window):
|
||||
position=tournament_button.button.get_screen_space_center(),
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.play import PlayWindow
|
||||
# def _back(self) -> None:
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.play import PlayWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
# If something is selected, store it.
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# # If something is selected, store it.
|
||||
# self._save_state()
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition=self._transition_out
|
||||
# )
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# PlayWindow(transition='in_left'), from_window=self, is_back=True
|
||||
# )
|
||||
|
||||
def _save_state(self) -> None:
|
||||
cfg = bui.app.config
|
||||
@ -1277,10 +1248,10 @@ class CoopBrowserWindow(bui.Window):
|
||||
sel = self._root_widget.get_selected_child()
|
||||
if sel == self._back_button:
|
||||
sel_name = 'Back'
|
||||
elif sel == self._store_button_widget:
|
||||
sel_name = 'Store'
|
||||
elif sel == self._league_rank_button_widget:
|
||||
sel_name = 'PowerRanking'
|
||||
# elif sel == self._store_button_widget:
|
||||
# sel_name = 'Store'
|
||||
# elif sel == self._league_rank_button_widget:
|
||||
# sel_name = 'PowerRanking'
|
||||
elif sel == self._scrollwidget:
|
||||
sel_name = 'Scroll'
|
||||
else:
|
||||
@ -1305,10 +1276,10 @@ class CoopBrowserWindow(bui.Window):
|
||||
sel = self._back_button
|
||||
elif sel_name == 'Scroll':
|
||||
sel = self._scrollwidget
|
||||
elif sel_name == 'PowerRanking':
|
||||
sel = self._league_rank_button_widget
|
||||
elif sel_name == 'Store':
|
||||
sel = self._store_button_widget
|
||||
# elif sel_name == 'PowerRanking':
|
||||
# sel = self._league_rank_button_widget
|
||||
# elif sel_name == 'Store':
|
||||
# sel = self._store_button_widget
|
||||
else:
|
||||
sel = self._scrollwidget
|
||||
bui.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||
|
||||
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
@ -14,30 +14,23 @@ if TYPE_CHECKING:
|
||||
from typing import Sequence
|
||||
|
||||
|
||||
class CreditsListWindow(bui.Window):
|
||||
class CreditsWindow(bui.MainWindow):
|
||||
"""Window for displaying game credits."""
|
||||
|
||||
def __init__(self, origin_widget: bui.Widget | None = None):
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
import json
|
||||
|
||||
bui.set_analytics_screen('Credits Window')
|
||||
|
||||
# if they provided an origin-widget, scale up from that
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
transition = 'in_right'
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 870 if uiscale is bui.UIScale.SMALL else 670
|
||||
width = 990 if uiscale is bui.UIScale.SMALL else 670
|
||||
x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
|
||||
height = 398 if uiscale is bui.UIScale.SMALL else 500
|
||||
|
||||
@ -45,36 +38,37 @@ class CreditsListWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
2.0
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.8
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.2 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -8) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
40 + x_inset,
|
||||
height - (68 if uiscale is bui.UIScale.SMALL else 62),
|
||||
),
|
||||
position=(40 + x_inset, height - 62),
|
||||
size=(140, 60),
|
||||
scale=0.8,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._back,
|
||||
on_activate_call=self.main_window_back,
|
||||
autoselect=True,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
@ -84,7 +78,7 @@ class CreditsListWindow(bui.Window):
|
||||
button_type='backSmall',
|
||||
position=(
|
||||
40 + x_inset,
|
||||
height - (68 if uiscale is bui.UIScale.SMALL else 62) + 5,
|
||||
height - 62 + 5,
|
||||
),
|
||||
size=(60, 48),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
@ -92,8 +86,9 @@ class CreditsListWindow(bui.Window):
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, height - (59 if uiscale is bui.UIScale.SMALL else 54)),
|
||||
position=(0, height - (65 if uiscale is bui.UIScale.SMALL else 54)),
|
||||
size=(width, 30),
|
||||
scale=0.8 if uiscale is bui.UIScale.SMALL else 1.0,
|
||||
text=bui.Lstr(
|
||||
resource=f'{self._r}.titleText',
|
||||
subs=[('${APP_NAME}', bui.Lstr(resource='titleText'))],
|
||||
@ -111,16 +106,15 @@ class CreditsListWindow(bui.Window):
|
||||
capture_arrows=True,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=scroll,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=scroll,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=scroll,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
|
||||
def _format_names(names2: Sequence[str], inset: float) -> str:
|
||||
sval = ''
|
||||
@ -354,18 +348,12 @@ class CreditsListWindow(bui.Window):
|
||||
)
|
||||
voffs -= line_height
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
@ -51,7 +51,7 @@ class DiscordWindow(bui.Window):
|
||||
)
|
||||
)
|
||||
|
||||
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._do_back
|
||||
)
|
||||
|
||||
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
||||
from typing import Any, Callable, Sequence
|
||||
|
||||
|
||||
class FileSelectorWindow(bui.Window):
|
||||
class FileSelectorWindow(bui.MainWindow):
|
||||
"""Window for selecting files."""
|
||||
|
||||
def __init__(
|
||||
@ -26,6 +26,8 @@ class FileSelectorWindow(bui.Window):
|
||||
show_base_path: bool = True,
|
||||
valid_file_extensions: Sequence[str] | None = None,
|
||||
allow_folders: bool = False,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
if valid_file_extensions is None:
|
||||
valid_file_extensions = []
|
||||
@ -51,7 +53,6 @@ class FileSelectorWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition='in_right',
|
||||
scale=(
|
||||
2.23
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
@ -60,7 +61,9 @@ class FileSelectorWindow(bui.Window):
|
||||
stack_offset=(
|
||||
(0, -35) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -135,6 +138,31 @@ class FileSelectorWindow(bui.Window):
|
||||
)
|
||||
self._set_path(path)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Pull everything out of self here. If we do it below in the lambda,
|
||||
# we'll keep self alive which is bad.
|
||||
path = self._base_path
|
||||
callback = self._callback
|
||||
show_base_path = self._show_base_path
|
||||
valid_file_extensions = self._valid_file_extensions
|
||||
allow_folders = self._allow_folders
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
path=path,
|
||||
callback=callback,
|
||||
show_base_path=show_base_path,
|
||||
valid_file_extensions=valid_file_extensions,
|
||||
allow_folders=allow_folders,
|
||||
)
|
||||
)
|
||||
|
||||
def _on_up_press(self) -> None:
|
||||
self._on_entry_activated('..')
|
||||
|
||||
@ -458,6 +486,7 @@ class FileSelectorWindow(bui.Window):
|
||||
)
|
||||
|
||||
def _cancel(self) -> None:
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
self.main_window_back()
|
||||
if self._callback is not None:
|
||||
self._callback(None)
|
||||
|
||||
@ -7,6 +7,7 @@ from __future__ import annotations
|
||||
import weakref
|
||||
import logging
|
||||
from enum import Enum
|
||||
from typing import override
|
||||
|
||||
from bauiv1lib.tabs import TabRow
|
||||
import bauiv1 as bui
|
||||
@ -52,7 +53,7 @@ class GatherTab:
|
||||
"""Called when the parent window is restoring state."""
|
||||
|
||||
|
||||
class GatherWindow(bui.Window):
|
||||
class GatherWindow(bui.MainWindow):
|
||||
"""Window for joining/inviting friends."""
|
||||
|
||||
class TabID(Enum):
|
||||
@ -82,22 +83,11 @@ class GatherWindow(bui.Window):
|
||||
assert plus is not None
|
||||
|
||||
bui.set_analytics_screen('Gather Window')
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_location('Gather')
|
||||
bui.set_party_icon_always_visible(True)
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 1440 if uiscale is bui.UIScale.SMALL else 1040
|
||||
self._width = 1640 if uiscale is bui.UIScale.SMALL else 1040
|
||||
x_offs = 200 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
582
|
||||
550
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 680 if uiscale is bui.UIScale.MEDIUM else 800
|
||||
)
|
||||
@ -108,25 +98,29 @@ class GatherWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + extra_top),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
1.3
|
||||
toolbar_visibility=(
|
||||
'menu_tokens'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 0.97 if uiscale is bui.UIScale.MEDIUM else 0.8
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.15
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 0.95 if uiscale is bui.UIScale.MEDIUM else 0.7
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -11)
|
||||
(0, -20)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (0, 0) if uiscale is bui.UIScale.MEDIUM else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._back_button = None
|
||||
else:
|
||||
@ -138,7 +132,7 @@ class GatherWindow(bui.Window):
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
bui.buttonwidget(
|
||||
@ -151,7 +145,7 @@ class GatherWindow(bui.Window):
|
||||
|
||||
condensed = uiscale is not bui.UIScale.LARGE
|
||||
t_offs_y = (
|
||||
0 if not condensed else 25 if uiscale is bui.UIScale.MEDIUM else 17
|
||||
0 if not condensed else 25 if uiscale is bui.UIScale.MEDIUM else 33
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -161,12 +155,12 @@ class GatherWindow(bui.Window):
|
||||
scale=(
|
||||
1.5
|
||||
if not condensed
|
||||
else 1.0 if uiscale is bui.UIScale.MEDIUM else 0.6
|
||||
else 1.0 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
text=bui.Lstr(resource=f'{self._r}.titleText'),
|
||||
maxwidth=550,
|
||||
maxwidth=320,
|
||||
)
|
||||
|
||||
scroll_buffer_h = 130 + 2 * x_offs
|
||||
@ -218,16 +212,15 @@ class GatherWindow(bui.Window):
|
||||
if tabtype is not None:
|
||||
self._tabs[tab_id] = tabtype(self)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=self._tab_row.tabs[tabdefs[-1][0]].button,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=self._tab_row.tabs[tabdefs[-1][0]].button,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
edit=self._tab_row.tabs[tabdefs[0][0]].button,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=self._tab_row.tabs[tabdefs[0][0]].button,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
|
||||
self._scroll_width = self._width - scroll_buffer_h
|
||||
self._scroll_height = self._height - 180.0 + tabs_top_extra
|
||||
@ -257,24 +250,36 @@ class GatherWindow(bui.Window):
|
||||
|
||||
self._restore_state()
|
||||
|
||||
def __del__(self) -> None:
|
||||
bui.set_party_icon_always_visible(False)
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def playlist_select(self, origin_widget: bui.Widget) -> None:
|
||||
"""Called by the private-hosting tab to select a playlist."""
|
||||
from bauiv1lib.play import PlayWindow
|
||||
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.selecting_private_party_playlist = True
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(origin_widget=origin_widget).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
classic.selecting_private_party_playlist = True
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlayWindow(origin_widget=origin_widget), from_window=self
|
||||
)
|
||||
|
||||
def _set_tab(self, tab_id: TabID) -> None:
|
||||
@ -340,8 +345,6 @@ class GatherWindow(bui.Window):
|
||||
logging.exception('Error saving state for %s.', self)
|
||||
|
||||
def _restore_state(self) -> None:
|
||||
from efro.util import enum_by_value
|
||||
|
||||
try:
|
||||
for tab in self._tabs.values():
|
||||
tab.restore_state()
|
||||
@ -354,7 +357,7 @@ class GatherWindow(bui.Window):
|
||||
current_tab = self.TabID.ABOUT
|
||||
gather_tab_val = bui.app.config.get('Gather Tab')
|
||||
try:
|
||||
stored_tab = enum_by_value(self.TabID, gather_tab_val)
|
||||
stored_tab = self.TabID(gather_tab_val)
|
||||
if stored_tab in self._tab_row.tabs:
|
||||
current_tab = stored_tab
|
||||
except ValueError:
|
||||
@ -366,9 +369,7 @@ class GatherWindow(bui.Window):
|
||||
sel = self._tab_container
|
||||
elif isinstance(sel_name, str) and sel_name.startswith('Tab:'):
|
||||
try:
|
||||
sel_tab_id = enum_by_value(
|
||||
self.TabID, sel_name.split(':')[-1]
|
||||
)
|
||||
sel_tab_id = self.TabID(sel_name.split(':')[-1])
|
||||
except ValueError:
|
||||
sel_tab_id = self.TabID.ABOUT
|
||||
sel = self._tab_row.tabs[sel_tab_id].button
|
||||
@ -378,20 +379,3 @@ class GatherWindow(bui.Window):
|
||||
|
||||
except Exception:
|
||||
logging.exception('Error restoring state for %s.', self)
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -157,6 +157,7 @@ class AboutGatherTab(GatherTab):
|
||||
autoselect=True,
|
||||
on_activate_call=bui.WeakCall(self._invite_to_try_press),
|
||||
up_widget=tab_button,
|
||||
show_buffer_top=500,
|
||||
)
|
||||
y -= invite_height
|
||||
else:
|
||||
|
||||
@ -89,10 +89,10 @@ class ManualGatherTab(GatherTab):
|
||||
self._container: bui.Widget | None = None
|
||||
self._join_by_address_text: bui.Widget | None = None
|
||||
self._favorites_text: bui.Widget | None = None
|
||||
self._width: int | None = None
|
||||
self._height: int | None = None
|
||||
self._scroll_width: int | None = None
|
||||
self._scroll_height: int | None = None
|
||||
self._width: float | None = None
|
||||
self._height: float | None = None
|
||||
self._scroll_width: float | None = None
|
||||
self._scroll_height: float | None = None
|
||||
self._favorites_scroll_width: int | None = None
|
||||
self._favorites_connect_button: bui.Widget | None = None
|
||||
self._scrollwidget: bui.Widget | None = None
|
||||
@ -241,7 +241,7 @@ class ManualGatherTab(GatherTab):
|
||||
self._build_join_by_address_tab(region_width, region_height)
|
||||
|
||||
if value is SubTabType.FAVORITES:
|
||||
self._build_favorites_tab(region_height)
|
||||
self._build_favorites_tab(region_width, region_height)
|
||||
|
||||
# The old manual tab
|
||||
def _build_join_by_address_tab(
|
||||
@ -276,7 +276,9 @@ class ManualGatherTab(GatherTab):
|
||||
maxwidth=380,
|
||||
size=(420, 60),
|
||||
)
|
||||
assert self._join_by_address_text is not None
|
||||
bui.widget(edit=self._join_by_address_text, down_widget=txt)
|
||||
assert self._favorites_text is not None
|
||||
bui.widget(edit=self._favorites_text, down_widget=txt)
|
||||
bui.textwidget(
|
||||
parent=self._container,
|
||||
@ -349,13 +351,16 @@ class ManualGatherTab(GatherTab):
|
||||
bui.widget(edit=self._check_button, up_widget=btn)
|
||||
|
||||
# Tab containing saved favorite addresses
|
||||
def _build_favorites_tab(self, region_height: float) -> None:
|
||||
def _build_favorites_tab(
|
||||
self, region_width: float, region_height: float
|
||||
) -> None:
|
||||
c_height = region_height - 20
|
||||
v = c_height - 35 - 25 - 30
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 1240 if uiscale is bui.UIScale.SMALL else 1040
|
||||
# self._width = 1240 if uiscale is bui.UIScale.SMALL else 1040
|
||||
self._width = region_width
|
||||
x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
578
|
||||
@ -400,7 +405,7 @@ class ManualGatherTab(GatherTab):
|
||||
self._favorites_connect_button = btn1 = bui.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(b_width, b_height),
|
||||
position=(40 if uiscale is bui.UIScale.SMALL else 40, btnv),
|
||||
position=(140 if uiscale is bui.UIScale.SMALL else 40, btnv),
|
||||
button_type='square',
|
||||
color=(0.6, 0.53, 0.63),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
@ -409,7 +414,7 @@ class ManualGatherTab(GatherTab):
|
||||
label=bui.Lstr(resource='gatherWindow.manualConnectText'),
|
||||
autoselect=True,
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=btn1,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
@ -418,7 +423,7 @@ class ManualGatherTab(GatherTab):
|
||||
bui.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(b_width, b_height),
|
||||
position=(40 if uiscale is bui.UIScale.SMALL else 40, btnv),
|
||||
position=(140 if uiscale is bui.UIScale.SMALL else 40, btnv),
|
||||
button_type='square',
|
||||
color=(0.6, 0.53, 0.63),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
@ -431,7 +436,7 @@ class ManualGatherTab(GatherTab):
|
||||
bui.buttonwidget(
|
||||
parent=self._container,
|
||||
size=(b_width, b_height),
|
||||
position=(40 if uiscale is bui.UIScale.SMALL else 40, btnv),
|
||||
position=(140 if uiscale is bui.UIScale.SMALL else 40, btnv),
|
||||
button_type='square',
|
||||
color=(0.6, 0.53, 0.63),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
@ -444,7 +449,7 @@ class ManualGatherTab(GatherTab):
|
||||
v -= sub_scroll_height + 23
|
||||
self._scrollwidget = scrlw = bui.scrollwidget(
|
||||
parent=self._container,
|
||||
position=(190 if uiscale is bui.UIScale.SMALL else 225, v),
|
||||
position=(290 if uiscale is bui.UIScale.SMALL else 225, v),
|
||||
size=(sub_scroll_width, sub_scroll_height),
|
||||
claims_left_right=True,
|
||||
)
|
||||
@ -469,7 +474,7 @@ class ManualGatherTab(GatherTab):
|
||||
scale=1.2,
|
||||
position=(
|
||||
(
|
||||
(190 if uiscale is bui.UIScale.SMALL else 225)
|
||||
(240 if uiscale is bui.UIScale.SMALL else 225)
|
||||
+ sub_scroll_width * 0.5
|
||||
),
|
||||
v + sub_scroll_height * 0.5,
|
||||
@ -760,6 +765,7 @@ class ManualGatherTab(GatherTab):
|
||||
claims_left_right=bool(servers),
|
||||
claims_up_down=bool(servers),
|
||||
)
|
||||
assert self._scrollwidget is not None
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
up_widget=self._favorites_text,
|
||||
|
||||
@ -559,7 +559,8 @@ class PrivateGatherTab(GatherTab):
|
||||
def _build_host_tab(self) -> None:
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
assert bui.app.classic is not None
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -636,41 +637,7 @@ class PrivateGatherTab(GatherTab):
|
||||
and hostingstate.tickets_to_host_now != 0
|
||||
and not havegoldpass
|
||||
):
|
||||
if not bui.app.ui_v1.use_toolbars:
|
||||
|
||||
# Currently have no allow_token_purchases value like
|
||||
# we had with tickets; just assuming we always allow.
|
||||
if bool(True):
|
||||
# if bui.app.classic.allow_ticket_purchases:
|
||||
self._get_tokens_button = bui.buttonwidget(
|
||||
parent=self._container,
|
||||
position=(
|
||||
self._c_width - 210 + 125,
|
||||
self._c_height - 44,
|
||||
),
|
||||
autoselect=True,
|
||||
scale=0.6,
|
||||
size=(120, 60),
|
||||
textcolor=(1.0, 0.6, 0.0),
|
||||
label=bui.charstr(bui.SpecialChar.TOKEN),
|
||||
color=(0.65, 0.5, 0.8),
|
||||
on_activate_call=self._on_get_tokens_press,
|
||||
)
|
||||
else:
|
||||
self._token_count_text = bui.textwidget(
|
||||
parent=self._container,
|
||||
scale=0.6,
|
||||
position=(
|
||||
self._c_width - 210 + 125,
|
||||
self._c_height - 44,
|
||||
),
|
||||
color=(1.0, 0.6, 0.0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
# Set initial token count.
|
||||
self._update_currency_ui()
|
||||
pass
|
||||
|
||||
v = self._c_height - 90
|
||||
if hostingstate.party_code is None:
|
||||
@ -689,7 +656,7 @@ class PrivateGatherTab(GatherTab):
|
||||
),
|
||||
)
|
||||
|
||||
v -= 100
|
||||
v -= 90
|
||||
if hostingstate.party_code is None:
|
||||
# We've got no current party running; show options to set
|
||||
# one up.
|
||||
@ -718,12 +685,12 @@ class PrivateGatherTab(GatherTab):
|
||||
|
||||
# If it appears we're coming back from playlist selection,
|
||||
# re-select our playlist button.
|
||||
if bui.app.ui_v1.selecting_private_party_playlist:
|
||||
if classic.selecting_private_party_playlist:
|
||||
bui.containerwidget(
|
||||
edit=self._container,
|
||||
selected_child=self._host_playlist_button,
|
||||
)
|
||||
bui.app.ui_v1.selecting_private_party_playlist = False
|
||||
classic.selecting_private_party_playlist = False
|
||||
else:
|
||||
# We've got a current party; show its info.
|
||||
bui.textwidget(
|
||||
@ -785,7 +752,7 @@ class PrivateGatherTab(GatherTab):
|
||||
autoselect=True,
|
||||
)
|
||||
|
||||
v -= 120
|
||||
v -= 110
|
||||
|
||||
# Line above the main action button:
|
||||
|
||||
@ -951,6 +918,9 @@ class PrivateGatherTab(GatherTab):
|
||||
)
|
||||
|
||||
def _playlist_press(self) -> None:
|
||||
if bool(True):
|
||||
bui.screenmessage('UNDER CONSTRUCTION')
|
||||
return
|
||||
assert self._host_playlist_button is not None
|
||||
self.window.playlist_select(origin_widget=self._host_playlist_button)
|
||||
|
||||
|
||||
@ -584,7 +584,7 @@ class PublicGatherTab(GatherTab):
|
||||
parent=self._container,
|
||||
text=self._filter_value,
|
||||
size=(350, 45),
|
||||
position=(290, v - 10),
|
||||
position=(c_width * 0.5 - 150, v - 10),
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
editable=True,
|
||||
@ -596,7 +596,7 @@ class PublicGatherTab(GatherTab):
|
||||
text=filter_txt,
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
position=(270, v + 13),
|
||||
position=(c_width * 0.5 - 170, v + 13),
|
||||
maxwidth=150,
|
||||
scale=0.8,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
@ -609,7 +609,7 @@ class PublicGatherTab(GatherTab):
|
||||
text=bui.Lstr(resource='nameText'),
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
position=(90, v - 8),
|
||||
position=((c_width - sub_scroll_width) * 0.5 + 50, v - 8),
|
||||
maxwidth=60,
|
||||
scale=0.6,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
@ -621,7 +621,10 @@ class PublicGatherTab(GatherTab):
|
||||
text=bui.Lstr(resource='gatherWindow.partySizeText'),
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
position=(755, v - 8),
|
||||
position=(
|
||||
c_width * 0.5 + sub_scroll_width * 0.5 - 110,
|
||||
v - 8,
|
||||
),
|
||||
maxwidth=60,
|
||||
scale=0.6,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
@ -633,7 +636,10 @@ class PublicGatherTab(GatherTab):
|
||||
text=bui.Lstr(resource='gatherWindow.pingText'),
|
||||
parent=self._container,
|
||||
size=(0, 0),
|
||||
position=(825, v - 8),
|
||||
position=(
|
||||
c_width * 0.5 + sub_scroll_width * 0.5 - 30,
|
||||
v - 8,
|
||||
),
|
||||
maxwidth=60,
|
||||
scale=0.6,
|
||||
color=(0.5, 0.46, 0.5),
|
||||
@ -811,6 +817,7 @@ class PublicGatherTab(GatherTab):
|
||||
bui.widget(edit=self._host_name_text, down_widget=btn2)
|
||||
bui.widget(edit=btn2, up_widget=self._host_name_text)
|
||||
bui.widget(edit=btn1, up_widget=self._host_name_text)
|
||||
assert self._join_text is not None
|
||||
bui.widget(edit=self._join_text, down_widget=self._host_name_text)
|
||||
v -= 10
|
||||
self._host_status_text = bui.textwidget(
|
||||
@ -897,11 +904,6 @@ class PublicGatherTab(GatherTab):
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
# Special case: if a party-queue window is up, don't do any of this
|
||||
# (keeps things smoother).
|
||||
# if bui.app.ui.have_party_queue_window:
|
||||
# return
|
||||
|
||||
if self._sub_tab is SubTabType.JOIN:
|
||||
# Keep our filter-text up to date from the UI.
|
||||
text = self._filter_text
|
||||
|
||||
@ -1,881 +0,0 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""UI functionality for purchasing/acquiring currency."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from efro.util import utc_now
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class GetTicketsWindow(bui.Window):
|
||||
"""Window for purchasing/acquiring classic tickets."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
from_modal_store: bool = False,
|
||||
modal: bool = False,
|
||||
origin_widget: bui.Widget | None = None,
|
||||
store_back_location: str | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
bui.set_analytics_screen('Get Tickets Window')
|
||||
|
||||
self._transitioning_out = False
|
||||
self._store_back_location = store_back_location # ew.
|
||||
|
||||
self._ad_button_greyed = False
|
||||
self._smooth_update_timer: bui.AppTimer | None = None
|
||||
self._ad_button = None
|
||||
self._ad_label = None
|
||||
self._ad_image = None
|
||||
self._ad_time_text = None
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 1000.0 if uiscale is bui.UIScale.SMALL else 800.0
|
||||
x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0
|
||||
self._height = 480.0
|
||||
|
||||
self._modal = modal
|
||||
self._from_modal_store = from_modal_store
|
||||
self._r = 'getTicketsWindow'
|
||||
|
||||
top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
color=(0.4, 0.37, 0.55),
|
||||
scale=(
|
||||
1.63
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.2 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -3) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(55 + x_inset, self._height - 79),
|
||||
size=(140, 60),
|
||||
scale=1.0,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='doneText' if modal else 'backText'),
|
||||
button_type='regular' if modal else 'back',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5 - 15, self._height - 47),
|
||||
size=(0, 0),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
scale=1.2,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
text=bui.Lstr(resource=f'{self._r}.titleText'),
|
||||
# text='Testing really long text here blah blah',
|
||||
maxwidth=260,
|
||||
)
|
||||
|
||||
# Get Tokens button
|
||||
bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 72),
|
||||
color=(0.65, 0.5, 0.7),
|
||||
textcolor=bui.app.ui_v1.title_color,
|
||||
size=(190, 50),
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='tokens.getTokensText'),
|
||||
on_activate_call=self._get_tokens_press,
|
||||
)
|
||||
|
||||
# 'New!' by tokens button
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=bui.Lstr(resource='newExclaimText'),
|
||||
position=(self._width * 0.5 + 25, self._height - 32),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 0, 1.0),
|
||||
rotate=22,
|
||||
shadow=1.0,
|
||||
maxwidth=150,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.7,
|
||||
)
|
||||
|
||||
if not modal:
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
b_size = (220.0, 180.0)
|
||||
v = self._height - b_size[1] - 80
|
||||
spacing = 1
|
||||
|
||||
self._ad_button = None
|
||||
|
||||
def _add_button(
|
||||
item: str,
|
||||
position: tuple[float, float],
|
||||
size: tuple[float, float],
|
||||
label: bui.Lstr,
|
||||
price: str | None = None,
|
||||
tex_name: str | None = None,
|
||||
tex_opacity: float = 1.0,
|
||||
tex_scale: float = 1.0,
|
||||
enabled: bool = True,
|
||||
text_scale: float = 1.0,
|
||||
) -> bui.Widget:
|
||||
btn2 = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=position,
|
||||
button_type='square',
|
||||
size=size,
|
||||
label='',
|
||||
autoselect=True,
|
||||
color=None if enabled else (0.5, 0.5, 0.5),
|
||||
on_activate_call=(
|
||||
bui.Call(self._purchase, item)
|
||||
if enabled
|
||||
else self._disabled_press
|
||||
),
|
||||
)
|
||||
txt = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=label,
|
||||
position=(
|
||||
position[0] + size[0] * 0.5,
|
||||
position[1] + size[1] * 0.3,
|
||||
),
|
||||
scale=text_scale,
|
||||
maxwidth=size[0] * 0.75,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
draw_controller=btn2,
|
||||
color=(0.7, 0.9, 0.7, 1.0 if enabled else 0.2),
|
||||
)
|
||||
if price is not None and enabled:
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=price,
|
||||
position=(
|
||||
position[0] + size[0] * 0.5,
|
||||
position[1] + size[1] * 0.17,
|
||||
),
|
||||
scale=0.7,
|
||||
maxwidth=size[0] * 0.75,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
draw_controller=btn2,
|
||||
color=(0.4, 0.9, 0.4, 1.0),
|
||||
)
|
||||
i = None
|
||||
if tex_name is not None:
|
||||
tex_size = 90.0 * tex_scale
|
||||
i = bui.imagewidget(
|
||||
parent=self._root_widget,
|
||||
texture=bui.gettexture(tex_name),
|
||||
position=(
|
||||
position[0] + size[0] * 0.5 - tex_size * 0.5,
|
||||
position[1] + size[1] * 0.66 - tex_size * 0.5,
|
||||
),
|
||||
size=(tex_size, tex_size),
|
||||
draw_controller=btn2,
|
||||
opacity=tex_opacity * (1.0 if enabled else 0.25),
|
||||
)
|
||||
if item == 'ad':
|
||||
self._ad_button = btn2
|
||||
self._ad_label = txt
|
||||
assert i is not None
|
||||
self._ad_image = i
|
||||
self._ad_time_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text='1m 10s',
|
||||
position=(
|
||||
position[0] + size[0] * 0.5,
|
||||
position[1] + size[1] * 0.5,
|
||||
),
|
||||
scale=text_scale * 1.2,
|
||||
maxwidth=size[0] * 0.85,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
draw_controller=btn2,
|
||||
color=(0.4, 0.9, 0.4, 1.0),
|
||||
)
|
||||
return btn2
|
||||
|
||||
rsrc = f'{self._r}.ticketsText'
|
||||
|
||||
c2txt = bui.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
str(
|
||||
plus.get_v1_account_misc_read_val('tickets2Amount', 500)
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
c3txt = bui.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
str(
|
||||
plus.get_v1_account_misc_read_val(
|
||||
'tickets3Amount', 1500
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
c4txt = bui.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
str(
|
||||
plus.get_v1_account_misc_read_val(
|
||||
'tickets4Amount', 5000
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
c5txt = bui.Lstr(
|
||||
resource=rsrc,
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
str(
|
||||
plus.get_v1_account_misc_read_val(
|
||||
'tickets5Amount', 15000
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
h = 110.0
|
||||
|
||||
# Enable buttons if we have prices.
|
||||
tickets2_price = plus.get_price('tickets2')
|
||||
tickets3_price = plus.get_price('tickets3')
|
||||
tickets4_price = plus.get_price('tickets4')
|
||||
tickets5_price = plus.get_price('tickets5')
|
||||
|
||||
# TEMP
|
||||
# tickets1_price = '$0.99'
|
||||
# tickets2_price = '$4.99'
|
||||
# tickets3_price = '$9.99'
|
||||
# tickets4_price = '$19.99'
|
||||
# tickets5_price = '$49.99'
|
||||
|
||||
_add_button(
|
||||
'tickets2',
|
||||
enabled=(tickets2_price is not None),
|
||||
position=(
|
||||
self._width * 0.5 - spacing * 1.5 - b_size[0] * 2.0 + h,
|
||||
v,
|
||||
),
|
||||
size=b_size,
|
||||
label=c2txt,
|
||||
price=tickets2_price,
|
||||
tex_name='ticketsMore',
|
||||
) # 0.99-ish
|
||||
_add_button(
|
||||
'tickets3',
|
||||
enabled=(tickets3_price is not None),
|
||||
position=(
|
||||
self._width * 0.5 - spacing * 0.5 - b_size[0] * 1.0 + h,
|
||||
v,
|
||||
),
|
||||
size=b_size,
|
||||
label=c3txt,
|
||||
price=tickets3_price,
|
||||
tex_name='ticketRoll',
|
||||
) # 4.99-ish
|
||||
v -= b_size[1] - 5
|
||||
_add_button(
|
||||
'tickets4',
|
||||
enabled=(tickets4_price is not None),
|
||||
position=(
|
||||
self._width * 0.5 - spacing * 1.5 - b_size[0] * 2.0 + h,
|
||||
v,
|
||||
),
|
||||
size=b_size,
|
||||
label=c4txt,
|
||||
price=tickets4_price,
|
||||
tex_name='ticketRollBig',
|
||||
tex_scale=1.2,
|
||||
) # 9.99-ish
|
||||
_add_button(
|
||||
'tickets5',
|
||||
enabled=(tickets5_price is not None),
|
||||
position=(
|
||||
self._width * 0.5 - spacing * 0.5 - b_size[0] * 1.0 + h,
|
||||
v,
|
||||
),
|
||||
size=b_size,
|
||||
label=c5txt,
|
||||
price=tickets5_price,
|
||||
tex_name='ticketRolls',
|
||||
tex_scale=1.2,
|
||||
) # 19.99-ish
|
||||
|
||||
self._enable_ad_button = plus.has_video_ads()
|
||||
h = self._width * 0.5 + 110.0
|
||||
v = self._height - b_size[1] - 115.0
|
||||
|
||||
if self._enable_ad_button:
|
||||
h_offs = 35
|
||||
b_size_3 = (150, 120)
|
||||
cdb = _add_button(
|
||||
'ad',
|
||||
position=(h + h_offs, v),
|
||||
size=b_size_3,
|
||||
label=bui.Lstr(
|
||||
resource=f'{self._r}.ticketsFromASponsorText',
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
str(
|
||||
plus.get_v1_account_misc_read_val(
|
||||
'sponsorTickets', 5
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
tex_name='ticketsMore',
|
||||
enabled=self._enable_ad_button,
|
||||
tex_opacity=0.6,
|
||||
tex_scale=0.7,
|
||||
text_scale=0.7,
|
||||
)
|
||||
bui.buttonwidget(edit=cdb, color=(0.65, 0.5, 0.7))
|
||||
|
||||
self._ad_free_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=bui.Lstr(resource=f'{self._r}.freeText'),
|
||||
position=(
|
||||
h + h_offs + b_size_3[0] * 0.5,
|
||||
v + b_size_3[1] * 0.5 + 25,
|
||||
),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 0, 1.0),
|
||||
draw_controller=cdb,
|
||||
rotate=15,
|
||||
shadow=1.0,
|
||||
maxwidth=150,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=1.0,
|
||||
)
|
||||
v -= 125
|
||||
else:
|
||||
v -= 20
|
||||
|
||||
if bool(True):
|
||||
h_offs = 35
|
||||
b_size_3 = (150, 120)
|
||||
cdb = _add_button(
|
||||
'app_invite',
|
||||
position=(h + h_offs, v),
|
||||
size=b_size_3,
|
||||
label=bui.Lstr(
|
||||
resource='gatherWindow.earnTicketsForRecommendingText',
|
||||
subs=[
|
||||
(
|
||||
'${COUNT}',
|
||||
str(
|
||||
plus.get_v1_account_misc_read_val(
|
||||
'sponsorTickets', 5
|
||||
)
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
tex_name='ticketsMore',
|
||||
enabled=True,
|
||||
tex_opacity=0.6,
|
||||
tex_scale=0.7,
|
||||
text_scale=0.7,
|
||||
)
|
||||
bui.buttonwidget(edit=cdb, color=(0.65, 0.5, 0.7))
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=bui.Lstr(resource=f'{self._r}.freeText'),
|
||||
position=(
|
||||
h + h_offs + b_size_3[0] * 0.5,
|
||||
v + b_size_3[1] * 0.5 + 25,
|
||||
),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 0, 1.0),
|
||||
draw_controller=cdb,
|
||||
rotate=15,
|
||||
shadow=1.0,
|
||||
maxwidth=150,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=1.0,
|
||||
)
|
||||
tc_y_offs = 0
|
||||
else:
|
||||
tc_y_offs = 0
|
||||
|
||||
h = self._width - (185 + x_inset)
|
||||
v = self._height - 105 + tc_y_offs
|
||||
|
||||
txt1 = (
|
||||
bui.Lstr(resource=f'{self._r}.youHaveText')
|
||||
.evaluate()
|
||||
.partition('${COUNT}')[0]
|
||||
.strip()
|
||||
)
|
||||
txt2 = (
|
||||
bui.Lstr(resource=f'{self._r}.youHaveText')
|
||||
.evaluate()
|
||||
.rpartition('${COUNT}')[-1]
|
||||
.strip()
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=txt1,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
color=(0.5, 0.5, 0.6),
|
||||
maxwidth=200,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.8,
|
||||
)
|
||||
v -= 30
|
||||
self._ticket_count_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
color=(0.2, 1.0, 0.2),
|
||||
maxwidth=200,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=1.6,
|
||||
)
|
||||
v -= 30
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=txt2,
|
||||
position=(h, v),
|
||||
size=(0, 0),
|
||||
color=(0.5, 0.5, 0.6),
|
||||
maxwidth=200,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.8,
|
||||
)
|
||||
|
||||
self._ticking_sound: bui.Sound | None = None
|
||||
self._smooth_ticket_count: float | None = None
|
||||
self._ticket_count = 0
|
||||
self._update()
|
||||
self._update_timer = bui.AppTimer(
|
||||
1.0, bui.WeakCall(self._update), repeat=True
|
||||
)
|
||||
self._smooth_increase_speed = 1.0
|
||||
|
||||
def __del__(self) -> None:
|
||||
if self._ticking_sound is not None:
|
||||
self._ticking_sound.stop()
|
||||
self._ticking_sound = None
|
||||
|
||||
def _smooth_update(self) -> None:
|
||||
if not self._ticket_count_text:
|
||||
self._smooth_update_timer = None
|
||||
return
|
||||
|
||||
finished = False
|
||||
|
||||
# If we're going down, do it immediately.
|
||||
assert self._smooth_ticket_count is not None
|
||||
if int(self._smooth_ticket_count) >= self._ticket_count:
|
||||
self._smooth_ticket_count = float(self._ticket_count)
|
||||
finished = True
|
||||
else:
|
||||
# We're going up; start a sound if need be.
|
||||
self._smooth_ticket_count = min(
|
||||
self._smooth_ticket_count + 1.0 * self._smooth_increase_speed,
|
||||
self._ticket_count,
|
||||
)
|
||||
if int(self._smooth_ticket_count) >= self._ticket_count:
|
||||
finished = True
|
||||
self._smooth_ticket_count = float(self._ticket_count)
|
||||
elif self._ticking_sound is None:
|
||||
self._ticking_sound = bui.getsound('scoreIncrease')
|
||||
self._ticking_sound.play()
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._ticket_count_text,
|
||||
text=str(int(self._smooth_ticket_count)),
|
||||
)
|
||||
|
||||
# If we've reached the target, kill the timer/sound/etc.
|
||||
if finished:
|
||||
self._smooth_update_timer = None
|
||||
if self._ticking_sound is not None:
|
||||
self._ticking_sound.stop()
|
||||
self._ticking_sound = None
|
||||
bui.getsound('cashRegister2').play()
|
||||
|
||||
def _update(self) -> None:
|
||||
import datetime
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
# If we somehow get signed out, just die.
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
self._back()
|
||||
return
|
||||
|
||||
self._ticket_count = plus.get_v1_account_ticket_count()
|
||||
|
||||
# Update our incentivized ad button depending on whether ads are
|
||||
# available.
|
||||
if self._ad_button is not None:
|
||||
next_reward_ad_time = plus.get_v1_account_misc_read_val_2(
|
||||
'nextRewardAdTime', None
|
||||
)
|
||||
if next_reward_ad_time is not None:
|
||||
next_reward_ad_time = datetime.datetime.fromtimestamp(
|
||||
next_reward_ad_time, datetime.UTC
|
||||
)
|
||||
now = utc_now()
|
||||
if plus.have_incentivized_ad() and (
|
||||
next_reward_ad_time is None or next_reward_ad_time <= now
|
||||
):
|
||||
self._ad_button_greyed = False
|
||||
bui.buttonwidget(edit=self._ad_button, color=(0.65, 0.5, 0.7))
|
||||
bui.textwidget(edit=self._ad_label, color=(0.7, 0.9, 0.7, 1.0))
|
||||
bui.textwidget(edit=self._ad_free_text, color=(1, 1, 0, 1))
|
||||
bui.imagewidget(edit=self._ad_image, opacity=0.6)
|
||||
bui.textwidget(edit=self._ad_time_text, text='')
|
||||
else:
|
||||
self._ad_button_greyed = True
|
||||
bui.buttonwidget(edit=self._ad_button, color=(0.5, 0.5, 0.5))
|
||||
bui.textwidget(edit=self._ad_label, color=(0.7, 0.9, 0.7, 0.2))
|
||||
bui.textwidget(edit=self._ad_free_text, color=(1, 1, 0, 0.2))
|
||||
bui.imagewidget(edit=self._ad_image, opacity=0.6 * 0.25)
|
||||
sval: str | bui.Lstr
|
||||
if (
|
||||
next_reward_ad_time is not None
|
||||
and next_reward_ad_time > now
|
||||
):
|
||||
sval = bui.timestring(
|
||||
(next_reward_ad_time - now).total_seconds(), centi=False
|
||||
)
|
||||
else:
|
||||
sval = ''
|
||||
bui.textwidget(edit=self._ad_time_text, text=sval)
|
||||
|
||||
# If this is our first update, assign immediately; otherwise kick
|
||||
# off a smooth transition if the value has changed.
|
||||
if self._smooth_ticket_count is None:
|
||||
self._smooth_ticket_count = float(self._ticket_count)
|
||||
self._smooth_update() # will set the text widget
|
||||
|
||||
elif (
|
||||
self._ticket_count != int(self._smooth_ticket_count)
|
||||
and self._smooth_update_timer is None
|
||||
):
|
||||
self._smooth_update_timer = bui.AppTimer(
|
||||
0.05, bui.WeakCall(self._smooth_update), repeat=True
|
||||
)
|
||||
diff = abs(float(self._ticket_count) - self._smooth_ticket_count)
|
||||
self._smooth_increase_speed = (
|
||||
diff / 100.0
|
||||
if diff >= 5000
|
||||
else (
|
||||
diff / 50.0
|
||||
if diff >= 1500
|
||||
else diff / 30.0 if diff >= 500 else diff / 15.0
|
||||
)
|
||||
)
|
||||
|
||||
def _disabled_press(self) -> None:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
# If we're on a platform without purchases, inform the user they
|
||||
# can link their accounts and buy stuff elsewhere.
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
if (
|
||||
app.env.test
|
||||
or (
|
||||
app.classic.platform == 'android'
|
||||
and app.classic.subplatform in ['oculus', 'cardboard']
|
||||
)
|
||||
) and plus.get_v1_account_misc_read_val('allowAccountLinking2', False):
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource=f'{self._r}.unavailableLinkAccountText'),
|
||||
color=(1, 0.5, 0),
|
||||
)
|
||||
else:
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource=f'{self._r}.unavailableText'),
|
||||
color=(1, 0.5, 0),
|
||||
)
|
||||
bui.getsound('error').play()
|
||||
|
||||
def _purchase(self, item: str) -> None:
|
||||
from bauiv1lib import account
|
||||
from bauiv1lib import appinvite
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
if bui.app.classic is None:
|
||||
raise RuntimeError('This requires classic support.')
|
||||
|
||||
if item == 'app_invite':
|
||||
if plus.get_v1_account_state() != 'signed_in':
|
||||
account.show_sign_in_prompt()
|
||||
return
|
||||
appinvite.handle_app_invites_press()
|
||||
return
|
||||
|
||||
# Here we ping the server to ask if it's valid for us to
|
||||
# purchase this.. (better to fail now than after we've paid
|
||||
# locally).
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
bui.app.classic.master_server_v1_get(
|
||||
'bsAccountPurchaseCheck',
|
||||
{
|
||||
'item': item,
|
||||
'platform': app.classic.platform,
|
||||
'subplatform': app.classic.subplatform,
|
||||
'version': app.env.engine_version,
|
||||
'buildNumber': app.env.engine_build_number,
|
||||
},
|
||||
callback=bui.WeakCall(self._purchase_check_result, item),
|
||||
)
|
||||
|
||||
def _purchase_check_result(
|
||||
self, item: str, result: dict[str, Any] | None
|
||||
) -> None:
|
||||
if result is None:
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='internal.unavailableNoConnectionText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
else:
|
||||
if result['allow']:
|
||||
self._do_purchase(item)
|
||||
else:
|
||||
if result['reason'] == 'versionTooOld':
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='getTicketsWindow.versionTooOldText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
else:
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='getTicketsWindow.unavailableText'),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
|
||||
# Actually start the purchase locally.
|
||||
def _do_purchase(self, item: str) -> None:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
if item == 'ad':
|
||||
import datetime
|
||||
|
||||
# If ads are disabled until some time, error.
|
||||
next_reward_ad_time = plus.get_v1_account_misc_read_val_2(
|
||||
'nextRewardAdTime', None
|
||||
)
|
||||
if next_reward_ad_time is not None:
|
||||
next_reward_ad_time = datetime.datetime.fromtimestamp(
|
||||
next_reward_ad_time, datetime.UTC
|
||||
)
|
||||
now = utc_now()
|
||||
if (
|
||||
next_reward_ad_time is not None and next_reward_ad_time > now
|
||||
) or self._ad_button_greyed:
|
||||
bui.getsound('error').play()
|
||||
bui.screenmessage(
|
||||
bui.Lstr(
|
||||
resource='getTicketsWindow.unavailableTemporarilyText'
|
||||
),
|
||||
color=(1, 0, 0),
|
||||
)
|
||||
elif self._enable_ad_button:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.classic.ads.show_ad('tickets')
|
||||
else:
|
||||
plus.purchase(item)
|
||||
|
||||
def _get_tokens_press(self) -> None:
|
||||
from functools import partial
|
||||
|
||||
from bauiv1lib.gettokens import GetTokensWindow
|
||||
|
||||
# No-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
if self._transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
# Note: Make sure we don't pass anything here that would
|
||||
# capture 'self'. (a lambda would implicitly do this by capturing
|
||||
# the stack frame).
|
||||
restorecall = partial(
|
||||
_restore_get_tickets_window,
|
||||
self._modal,
|
||||
self._from_modal_store,
|
||||
self._store_back_location,
|
||||
)
|
||||
|
||||
window = GetTokensWindow(
|
||||
transition='in_right',
|
||||
restore_previous_call=restorecall,
|
||||
).get_root_widget()
|
||||
if not self._modal and not self._from_modal_store:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
window, from_window=self._root_widget
|
||||
)
|
||||
self._transitioning_out = True
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.store import browser
|
||||
|
||||
# No-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
if self._transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if not self._modal:
|
||||
window = browser.StoreBrowserWindow(
|
||||
transition='in_left',
|
||||
modal=self._from_modal_store,
|
||||
back_location=self._store_back_location,
|
||||
).get_root_widget()
|
||||
if not self._from_modal_store:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
window, from_window=self._root_widget
|
||||
)
|
||||
self._transitioning_out = True
|
||||
|
||||
|
||||
# A call we can bundle up and pass to windows we open; allows them to
|
||||
# get back to us without having to explicitly know about us.
|
||||
def _restore_get_tickets_window(
|
||||
modal: bool,
|
||||
from_modal_store: bool,
|
||||
store_back_location: str | None,
|
||||
from_window: bui.Widget,
|
||||
) -> None:
|
||||
restored = GetTicketsWindow(
|
||||
transition='in_left',
|
||||
modal=modal,
|
||||
from_modal_store=from_modal_store,
|
||||
store_back_location=store_back_location,
|
||||
)
|
||||
if not modal and not from_modal_store:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
restored.get_root_widget(), from_window=from_window
|
||||
)
|
||||
|
||||
|
||||
def show_get_tickets_prompt() -> None:
|
||||
"""Show a 'not enough tickets' prompt with an option to purchase more.
|
||||
|
||||
Note that the purchase option may not always be available
|
||||
depending on the build of the game.
|
||||
"""
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
|
||||
if bui.app.classic.allow_ticket_purchases:
|
||||
ConfirmWindow(
|
||||
bui.Lstr(
|
||||
translate=(
|
||||
'serverResponses',
|
||||
'You don\'t have enough tickets for this!',
|
||||
)
|
||||
),
|
||||
lambda: GetTicketsWindow(modal=True),
|
||||
ok_text=bui.Lstr(resource='getTicketsWindow.titleText'),
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
else:
|
||||
ConfirmWindow(
|
||||
bui.Lstr(
|
||||
translate=(
|
||||
'serverResponses',
|
||||
'You don\'t have enough tickets for this!',
|
||||
)
|
||||
),
|
||||
cancel_button=False,
|
||||
width=460,
|
||||
height=130,
|
||||
)
|
||||
@ -325,56 +325,74 @@ class GetTokensWindow(bui.Window):
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 1000.0 if uiscale is bui.UIScale.SMALL else 800.0
|
||||
self._x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0
|
||||
self._height = 480.0
|
||||
self._x_inset = 25.0 if uiscale is bui.UIScale.SMALL else 0.0
|
||||
self._height = 550 if uiscale is bui.UIScale.SMALL else 480.0
|
||||
self._y_offset = -60 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
self._r = 'getTokensWindow'
|
||||
|
||||
top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
size=(self._width, self._height),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
color=(0.3, 0.23, 0.36),
|
||||
scale=(
|
||||
1.63
|
||||
1.5
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.2 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -3) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
# toolbar_visibility='menu_minimal',
|
||||
toolbar_visibility='get_tokens',
|
||||
)
|
||||
)
|
||||
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(45 + self._x_inset, self._height - 80),
|
||||
size=(
|
||||
(140, 60) if self._restore_previous_call is None else (60, 60)
|
||||
),
|
||||
scale=1.0,
|
||||
autoselect=True,
|
||||
label=(
|
||||
bui.Lstr(resource='doneText')
|
||||
if self._restore_previous_call is None
|
||||
else bui.charstr(bui.SpecialChar.BACK)
|
||||
),
|
||||
button_type=(
|
||||
'regular'
|
||||
if self._restore_previous_call is None
|
||||
else 'backSmall'
|
||||
),
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
)
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
else:
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
55 + self._x_inset,
|
||||
self._height - 80 + self._y_offset,
|
||||
),
|
||||
size=(
|
||||
(140, 60)
|
||||
if self._restore_previous_call is None
|
||||
else (60, 60)
|
||||
),
|
||||
scale=1.0,
|
||||
autoselect=True,
|
||||
label=(
|
||||
bui.Lstr(resource='doneText')
|
||||
if self._restore_previous_call is None
|
||||
else bui.charstr(bui.SpecialChar.BACK)
|
||||
),
|
||||
button_type=(
|
||||
'regular'
|
||||
if self._restore_previous_call is None
|
||||
else 'backSmall'
|
||||
),
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
# if uiscale is bui.UIScale.SMALL:
|
||||
# bui.widget(
|
||||
# edit=self._back_button,
|
||||
# up_widget=bui.get_special_widget('tokens_meter'),
|
||||
# )
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 47),
|
||||
position=(self._width * 0.5, self._height - 42 + self._y_offset),
|
||||
size=(0, 0),
|
||||
color=self._textcolor,
|
||||
flatness=0.0,
|
||||
@ -403,12 +421,12 @@ class GetTokensWindow(bui.Window):
|
||||
self._status_text,
|
||||
]
|
||||
|
||||
self._token_count_widget: bui.Widget | None = None
|
||||
self._smooth_update_timer: bui.AppTimer | None = None
|
||||
self._smooth_token_count: float | None = None
|
||||
self._token_count: int = 0
|
||||
self._smooth_increase_speed = 1.0
|
||||
self._ticking_sound: bui.Sound | None = None
|
||||
# self._token_count_widget: bui.Widget | None = None
|
||||
# self._smooth_update_timer: bui.AppTimer | None = None
|
||||
# self._smooth_token_count: float | None = None
|
||||
# self._token_count: int = 0
|
||||
# self._smooth_increase_speed = 1.0
|
||||
# self._ticking_sound: bui.Sound | None = None
|
||||
|
||||
# Get all textures used by our buttons preloading so hopefully
|
||||
# they'll be in place by the time we show them.
|
||||
@ -423,10 +441,10 @@ class GetTokensWindow(bui.Window):
|
||||
)
|
||||
self._update()
|
||||
|
||||
def __del__(self) -> None:
|
||||
if self._ticking_sound is not None:
|
||||
self._ticking_sound.stop()
|
||||
self._ticking_sound = None
|
||||
# def __del__(self) -> None:
|
||||
# if self._ticking_sound is not None:
|
||||
# self._ticking_sound.stop()
|
||||
# self._ticking_sound = None
|
||||
|
||||
def _update(self) -> None:
|
||||
# No-op if our underlying widget is dead or on its way out.
|
||||
@ -475,7 +493,7 @@ class GetTokensWindow(bui.Window):
|
||||
return
|
||||
|
||||
# Ok, state is changing. Start by resetting to a blank slate.
|
||||
self._token_count_widget = None
|
||||
# self._token_count_widget = None
|
||||
for widget in self._root_widget.get_children():
|
||||
if widget not in self._core_widgets:
|
||||
widget.delete()
|
||||
@ -527,6 +545,8 @@ class GetTokensWindow(bui.Window):
|
||||
# pylint: disable=too-many-locals
|
||||
plus = bui.app.plus
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
|
||||
bui.textwidget(edit=self._status_text, text='')
|
||||
|
||||
xinset = 40
|
||||
@ -540,17 +560,23 @@ class GetTokensWindow(bui.Window):
|
||||
# We currently don't handle the zero-button case.
|
||||
assert self._buttondefs
|
||||
|
||||
total_button_width = sum(
|
||||
b.width + b.prepad for b in self._buttondefs
|
||||
) + buttonpadding * (len(self._buttondefs) - 1)
|
||||
sidepad = 10.0
|
||||
total_button_width = (
|
||||
sum(b.width + b.prepad for b in self._buttondefs)
|
||||
+ buttonpadding * (len(self._buttondefs) - 1)
|
||||
+ 2 * sidepad
|
||||
)
|
||||
|
||||
h_scroll = bui.hscrollwidget(
|
||||
parent=self._root_widget,
|
||||
size=(scrollwidth, scrollheight),
|
||||
position=(self._x_inset + xinset, 45),
|
||||
position=(
|
||||
self._x_inset + xinset,
|
||||
self._height - 415 + self._y_offset,
|
||||
),
|
||||
claims_left_right=True,
|
||||
highlight=False,
|
||||
border_opacity=0.25,
|
||||
border_opacity=0.3 if uiscale is bui.UIScale.SMALL else 1.0,
|
||||
)
|
||||
subcontainer = bui.containerwidget(
|
||||
parent=h_scroll,
|
||||
@ -561,7 +587,10 @@ class GetTokensWindow(bui.Window):
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='learnMoreText'),
|
||||
position=(self._width * 0.5 - 75, self._height * 0.703),
|
||||
position=(
|
||||
self._width * 0.5 - 75,
|
||||
self._height - 125 + self._y_offset,
|
||||
),
|
||||
size=(180, 43),
|
||||
scale=0.8,
|
||||
color=(0.4, 0.25, 0.5),
|
||||
@ -570,8 +599,19 @@ class GetTokensWindow(bui.Window):
|
||||
self._on_learn_more_press, response.token_info_url
|
||||
),
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=tinfobtn,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
up_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
|
||||
x = 0.0
|
||||
bui.widget(
|
||||
edit=tinfobtn,
|
||||
right_widget=bui.get_special_widget('tokens_meter'),
|
||||
)
|
||||
|
||||
x = sidepad
|
||||
bwidgets: list[bui.Widget] = []
|
||||
for i, buttondef in enumerate(self._buttondefs):
|
||||
|
||||
@ -594,6 +634,10 @@ class GetTokensWindow(bui.Window):
|
||||
),
|
||||
)
|
||||
bwidgets.append(btn)
|
||||
|
||||
if i == 0:
|
||||
bui.widget(edit=btn, left_widget=self._back_button)
|
||||
|
||||
for imgdef in buttondef.imgdefs:
|
||||
_img = bui.imagewidget(
|
||||
parent=subcontainer,
|
||||
@ -645,7 +689,7 @@ class GetTokensWindow(bui.Window):
|
||||
|
||||
_tinfotxt = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.812),
|
||||
position=(self._width * 0.5, self._height - 70 + self._y_offset),
|
||||
color=self._textcolor,
|
||||
shadow=1.0,
|
||||
scale=0.7,
|
||||
@ -654,29 +698,35 @@ class GetTokensWindow(bui.Window):
|
||||
v_align='center',
|
||||
text=bui.Lstr(resource='tokens.shinyNewCurrencyText'),
|
||||
)
|
||||
self._token_count_widget = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width - self._x_inset - 120.0, self._height - 48),
|
||||
color=(2.0, 0.7, 0.0),
|
||||
shadow=1.0,
|
||||
flatness=0.0,
|
||||
size=(0, 0),
|
||||
h_align='left',
|
||||
v_align='center',
|
||||
text='',
|
||||
)
|
||||
self._token_count = response.tokens
|
||||
self._smooth_token_count = float(self._token_count)
|
||||
self._smooth_update() # will set the text widget.
|
||||
# self._token_count_widget = bui.textwidget(
|
||||
# parent=self._root_widget,
|
||||
# position=(
|
||||
# self._width - self._x_inset - 120.0,
|
||||
# self._height - 48 + self._y_offset,
|
||||
# ),
|
||||
# color=(2.0, 0.7, 0.0),
|
||||
# shadow=1.0,
|
||||
# flatness=0.0,
|
||||
# size=(0, 0),
|
||||
# h_align='left',
|
||||
# v_align='center',
|
||||
# text='',
|
||||
# )
|
||||
# self._token_count = response.tokens
|
||||
# self._smooth_token_count = float(self._token_count)
|
||||
# self._smooth_update() # will set the text widget.
|
||||
|
||||
_tlabeltxt = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width - self._x_inset - 123.0, self._height - 48),
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
text=bui.charstr(bui.SpecialChar.TOKEN),
|
||||
)
|
||||
# _tlabeltxt = bui.textwidget(
|
||||
# parent=self._root_widget,
|
||||
# position=(
|
||||
# self._width - self._x_inset - 123.0,
|
||||
# self._height - 48 + self._y_offset,
|
||||
# ),
|
||||
# size=(0, 0),
|
||||
# h_align='right',
|
||||
# v_align='center',
|
||||
# text=bui.charstr(bui.SpecialChar.TOKEN),
|
||||
# )
|
||||
|
||||
def _purchase_press(self, itemid: str) -> None:
|
||||
plus = bui.app.plus
|
||||
@ -700,70 +750,70 @@ class GetTokensWindow(bui.Window):
|
||||
|
||||
def _update_store_state(self) -> None:
|
||||
"""Called to make minor updates to an already shown store."""
|
||||
assert self._token_count_widget is not None
|
||||
# assert self._token_count_widget is not None
|
||||
assert self._last_query_response is not None
|
||||
|
||||
self._token_count = self._last_query_response.tokens
|
||||
# self._token_count = self._last_query_response.tokens
|
||||
|
||||
# Kick off new smooth update if need be.
|
||||
assert self._smooth_token_count is not None
|
||||
if (
|
||||
self._token_count != int(self._smooth_token_count)
|
||||
and self._smooth_update_timer is None
|
||||
):
|
||||
self._smooth_update_timer = bui.AppTimer(
|
||||
0.05, bui.WeakCall(self._smooth_update), repeat=True
|
||||
)
|
||||
diff = abs(float(self._token_count) - self._smooth_token_count)
|
||||
self._smooth_increase_speed = (
|
||||
diff / 100.0
|
||||
if diff >= 5000
|
||||
else (
|
||||
diff / 50.0
|
||||
if diff >= 1500
|
||||
else diff / 30.0 if diff >= 500 else diff / 15.0
|
||||
)
|
||||
)
|
||||
# assert self._smooth_token_count is not None
|
||||
# if (
|
||||
# self._token_count != int(self._smooth_token_count)
|
||||
# and self._smooth_update_timer is None
|
||||
# ):
|
||||
# self._smooth_update_timer = bui.AppTimer(
|
||||
# 0.05, bui.WeakCall(self._smooth_update), repeat=True
|
||||
# )
|
||||
# diff = abs(float(self._token_count) - self._smooth_token_count)
|
||||
# self._smooth_increase_speed = (
|
||||
# diff / 100.0
|
||||
# if diff >= 5000
|
||||
# else (
|
||||
# diff / 50.0
|
||||
# if diff >= 1500
|
||||
# else diff / 30.0 if diff >= 500 else diff / 15.0
|
||||
# )
|
||||
# )
|
||||
|
||||
def _smooth_update(self) -> None:
|
||||
# def _smooth_update(self) -> None:
|
||||
|
||||
# Stop if the count widget disappears.
|
||||
if not self._token_count_widget:
|
||||
self._smooth_update_timer = None
|
||||
return
|
||||
# # Stop if the count widget disappears.
|
||||
# if not self._token_count_widget:
|
||||
# self._smooth_update_timer = None
|
||||
# return
|
||||
|
||||
finished = False
|
||||
# finished = False
|
||||
|
||||
# If we're going down, do it immediately.
|
||||
assert self._smooth_token_count is not None
|
||||
if int(self._smooth_token_count) >= self._token_count:
|
||||
self._smooth_token_count = float(self._token_count)
|
||||
finished = True
|
||||
else:
|
||||
# We're going up; start a sound if need be.
|
||||
self._smooth_token_count = min(
|
||||
self._smooth_token_count + 1.0 * self._smooth_increase_speed,
|
||||
self._token_count,
|
||||
)
|
||||
if int(self._smooth_token_count) >= self._token_count:
|
||||
finished = True
|
||||
self._smooth_token_count = float(self._token_count)
|
||||
elif self._ticking_sound is None:
|
||||
self._ticking_sound = bui.getsound('scoreIncrease')
|
||||
self._ticking_sound.play()
|
||||
# # If we're going down, do it immediately.
|
||||
# assert self._smooth_token_count is not None
|
||||
# if int(self._smooth_token_count) >= self._token_count:
|
||||
# self._smooth_token_count = float(self._token_count)
|
||||
# finished = True
|
||||
# else:
|
||||
# # We're going up; start a sound if need be.
|
||||
# self._smooth_token_count = min(
|
||||
# self._smooth_token_count + 1.0 * self._smooth_increase_speed,
|
||||
# self._token_count,
|
||||
# )
|
||||
# if int(self._smooth_token_count) >= self._token_count:
|
||||
# finished = True
|
||||
# self._smooth_token_count = float(self._token_count)
|
||||
# elif self._ticking_sound is None:
|
||||
# self._ticking_sound = bui.getsound('scoreIncrease')
|
||||
# self._ticking_sound.play()
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._token_count_widget,
|
||||
text=str(int(self._smooth_token_count)),
|
||||
)
|
||||
# bui.textwidget(
|
||||
# edit=self._token_count_widget,
|
||||
# text=str(int(self._smooth_token_count)),
|
||||
# )
|
||||
|
||||
# If we've reached the target, kill the timer/sound/etc.
|
||||
if finished:
|
||||
self._smooth_update_timer = None
|
||||
if self._ticking_sound is not None:
|
||||
self._ticking_sound.stop()
|
||||
self._ticking_sound = None
|
||||
bui.getsound('cashRegister2').play()
|
||||
# # If we've reached the target, kill the timer/sound/etc.
|
||||
# if finished:
|
||||
# self._smooth_update_timer = None
|
||||
# if self._ticking_sound is not None:
|
||||
# self._ticking_sound.stop()
|
||||
# self._ticking_sound = None
|
||||
# bui.getsound('cashRegister2').play()
|
||||
|
||||
def _back(self) -> None:
|
||||
|
||||
|
||||
@ -4,40 +4,33 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class HelpWindow(bui.Window):
|
||||
class HelpWindow(bui.MainWindow):
|
||||
"""A window providing help on how to play."""
|
||||
|
||||
def __init__(
|
||||
self, main_menu: bool = False, origin_widget: bui.Widget | None = None
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
bui.set_analytics_screen('Help Window')
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
transition = 'in_right'
|
||||
|
||||
self._r = 'helpWindow'
|
||||
|
||||
getres = bui.app.lang.get_resource
|
||||
|
||||
self._main_menu = main_menu
|
||||
# self._main_menu = main_menu
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 1050 if uiscale is bui.UIScale.SMALL else 750
|
||||
x_offs = 150 if uiscale is bui.UIScale.SMALL else 0
|
||||
x_offs = 70 if uiscale is bui.UIScale.SMALL else 0
|
||||
height = (
|
||||
460
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
@ -47,20 +40,24 @@ class HelpWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
1.77
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.25 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.55
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.15 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -30)
|
||||
(0, -24)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (0, 15) if uiscale is bui.UIScale.MEDIUM else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
@ -87,20 +84,19 @@ class HelpWindow(bui.Window):
|
||||
capture_arrows=True,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._scrollwidget
|
||||
)
|
||||
|
||||
# ugly: create this last so it gets first dibs at touch events (since
|
||||
# we have it close to the scroll widget)
|
||||
if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._close
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
@ -109,33 +105,18 @@ class HelpWindow(bui.Window):
|
||||
else:
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
x_offs + (40 + 0 if uiscale is bui.UIScale.SMALL else 70),
|
||||
height - (59 if uiscale is bui.UIScale.SMALL else 50),
|
||||
),
|
||||
size=(140, 60),
|
||||
scale=0.7 if uiscale is bui.UIScale.SMALL else 0.8,
|
||||
label=(
|
||||
bui.Lstr(resource='backText')
|
||||
if self._main_menu
|
||||
else 'Close'
|
||||
),
|
||||
button_type='back' if self._main_menu else None,
|
||||
position=(x_offs + 50, height - 55),
|
||||
size=(60, 55),
|
||||
scale=0.8,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
extra_touch_border_scale=2.0,
|
||||
autoselect=True,
|
||||
on_activate_call=self._close,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
if self._main_menu:
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 55),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
self._sub_width = 660
|
||||
self._sub_width = 810 if uiscale is bui.UIScale.SMALL else 660
|
||||
self._sub_height = (
|
||||
1590
|
||||
+ bui.app.lang.get_resource(f'{self._r}.someDaysExtraSpace')
|
||||
@ -639,20 +620,12 @@ class HelpWindow(bui.Window):
|
||||
res_scale=0.5,
|
||||
)
|
||||
|
||||
def _close(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if self._main_menu:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
119
src/assets/ba_data/python/bauiv1lib/inbox.py
Normal file
119
src/assets/ba_data/python/bauiv1lib/inbox.py
Normal file
@ -0,0 +1,119 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides a popup window to view achievements."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
from bauiv1lib.popup import PopupWindow
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class InboxWindow(PopupWindow):
|
||||
"""Popup window to show account messages."""
|
||||
|
||||
def __init__(
|
||||
self, position: tuple[float, float], scale: float | None = None
|
||||
):
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
if scale is None:
|
||||
scale = (
|
||||
2.3
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
)
|
||||
self._transitioning_out = False
|
||||
self._width = 450
|
||||
self._height = (
|
||||
300
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 370 if uiscale is bui.UIScale.MEDIUM else 450
|
||||
)
|
||||
bg_color = (0.5, 0.4, 0.6)
|
||||
|
||||
# creates our _root_widget
|
||||
super().__init__(
|
||||
position=position,
|
||||
size=(self._width, self._height),
|
||||
scale=scale,
|
||||
bg_color=bg_color,
|
||||
edge_buffer_scale=4.0, # Try to keep button unobscured.
|
||||
)
|
||||
|
||||
self._cancel_button = bui.buttonwidget(
|
||||
parent=self.root_widget,
|
||||
position=(50, self._height - 30),
|
||||
size=(50, 50),
|
||||
scale=0.5,
|
||||
label='',
|
||||
color=bg_color,
|
||||
on_activate_call=self._on_cancel_press,
|
||||
autoselect=True,
|
||||
icon=bui.gettexture('crossOut'),
|
||||
iconscale=1.2,
|
||||
)
|
||||
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self.root_widget,
|
||||
position=(self._width * 0.5, self._height - 20),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.6,
|
||||
text='INBOX (UNDER CONSTRUCTION)',
|
||||
maxwidth=200,
|
||||
color=bui.app.ui_v1.title_color,
|
||||
)
|
||||
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
parent=self.root_widget,
|
||||
size=(self._width - 60, self._height - 70),
|
||||
position=(30, 30),
|
||||
capture_arrows=True,
|
||||
simple_culling_v=10,
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self.root_widget, cancel_button=self._cancel_button
|
||||
)
|
||||
|
||||
entries: list[str] = []
|
||||
incr = 20
|
||||
sub_width = self._width - 90
|
||||
sub_height = 40 + len(entries) * incr
|
||||
|
||||
self._subcontainer = bui.containerwidget(
|
||||
parent=self._scrollwidget,
|
||||
size=(sub_width, sub_height),
|
||||
background=False,
|
||||
)
|
||||
|
||||
for i, entry in enumerate(entries):
|
||||
bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(sub_width * 0.08 - 5, sub_height - 20 - incr * i),
|
||||
maxwidth=20,
|
||||
scale=0.5,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
text=entry,
|
||||
size=(0, 0),
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
def _on_cancel_press(self) -> None:
|
||||
self._transition_out()
|
||||
|
||||
def _transition_out(self) -> None:
|
||||
if not self._transitioning_out:
|
||||
self._transitioning_out = True
|
||||
bui.containerwidget(edit=self.root_widget, transition='out_scale')
|
||||
|
||||
@override
|
||||
def on_popup_cancel(self) -> None:
|
||||
bui.getsound('swish').play()
|
||||
self._transition_out()
|
||||
590
src/assets/ba_data/python/bauiv1lib/ingamemenu.py
Normal file
590
src/assets/ba_data/python/bauiv1lib/ingamemenu.py
Normal file
@ -0,0 +1,590 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Implements the in-gmae menu window."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, override
|
||||
import logging
|
||||
|
||||
import bauiv1 as bui
|
||||
import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
class InGameMenuWindow(bui.MainWindow):
|
||||
"""The menu that can be invoked while in a game."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
|
||||
# Make a vanilla container; we'll modify it to our needs in
|
||||
# refresh.
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
toolbar_visibility=('menu_in_game')
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
# Grab this stuff in case it changes.
|
||||
self._is_demo = bui.app.env.demo
|
||||
self._is_arcade = bui.app.env.arcade
|
||||
|
||||
self._p_index = 0
|
||||
self._use_autoselect = True
|
||||
self._button_width = 200.0
|
||||
self._button_height = 45.0
|
||||
self._width = 100.0
|
||||
self._height = 100.0
|
||||
|
||||
self._refresh()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def _refresh(self) -> None:
|
||||
|
||||
# Clear everything that was there.
|
||||
children = self._root_widget.get_children()
|
||||
for child in children:
|
||||
child.delete()
|
||||
|
||||
self._r = 'mainMenu'
|
||||
|
||||
self._input_device = input_device = bs.get_ui_input_device()
|
||||
|
||||
# Are we connected to a local player?
|
||||
self._input_player = input_device.player if input_device else None
|
||||
|
||||
# Are we connected to a remote player?.
|
||||
self._connected_to_remote_player = (
|
||||
input_device.is_attached_to_player()
|
||||
if (input_device and self._input_player is None)
|
||||
else False
|
||||
)
|
||||
|
||||
positions: list[tuple[float, float, float]] = []
|
||||
self._p_index = 0
|
||||
|
||||
self._refresh_in_game(positions)
|
||||
|
||||
h, v, scale = positions[self._p_index]
|
||||
self._p_index += 1
|
||||
|
||||
# If we're in a replay, we have a 'Leave Replay' button.
|
||||
if bs.is_in_replay():
|
||||
bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width * 0.5 * scale, v),
|
||||
scale=scale,
|
||||
size=(self._button_width, self._button_height),
|
||||
autoselect=self._use_autoselect,
|
||||
label=bui.Lstr(resource='replayEndText'),
|
||||
on_activate_call=self._confirm_end_replay,
|
||||
)
|
||||
elif bs.get_foreground_host_session() is not None:
|
||||
bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width * 0.5 * scale, v),
|
||||
scale=scale,
|
||||
size=(self._button_width, self._button_height),
|
||||
autoselect=self._use_autoselect,
|
||||
label=bui.Lstr(
|
||||
resource=self._r
|
||||
+ (
|
||||
'.endTestText'
|
||||
if self._is_benchmark()
|
||||
else '.endGameText'
|
||||
)
|
||||
),
|
||||
on_activate_call=(
|
||||
self._confirm_end_test
|
||||
if self._is_benchmark()
|
||||
else self._confirm_end_game
|
||||
),
|
||||
)
|
||||
else:
|
||||
# Assume we're in a client-session.
|
||||
bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width * 0.5 * scale, v),
|
||||
scale=scale,
|
||||
size=(self._button_width, self._button_height),
|
||||
autoselect=self._use_autoselect,
|
||||
label=bui.Lstr(resource=f'{self._r}.leavePartyText'),
|
||||
on_activate_call=self._confirm_leave_party,
|
||||
)
|
||||
|
||||
# Add speed-up/slow-down buttons for replays. Ideally this
|
||||
# should be part of a fading-out playback bar like most media
|
||||
# players but this works for now.
|
||||
if bs.is_in_replay():
|
||||
b_size = 50.0
|
||||
b_buffer_1 = 50.0
|
||||
b_buffer_2 = 10.0
|
||||
t_scale = 0.75
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
b_size *= 0.6
|
||||
b_buffer_1 *= 0.8
|
||||
b_buffer_2 *= 1.0
|
||||
v_offs = -40
|
||||
t_scale = 0.5
|
||||
elif uiscale is bui.UIScale.MEDIUM:
|
||||
v_offs = -70
|
||||
else:
|
||||
v_offs = -100
|
||||
self._replay_speed_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
text=bui.Lstr(
|
||||
resource='watchWindow.playbackSpeedText',
|
||||
subs=[('${SPEED}', str(1.23))],
|
||||
),
|
||||
position=(h, v + v_offs + 15 * t_scale),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
size=(0, 0),
|
||||
scale=t_scale,
|
||||
)
|
||||
|
||||
# Update to current value.
|
||||
self._change_replay_speed(0)
|
||||
|
||||
# Keep updating in a timer in case it gets changed elsewhere.
|
||||
self._change_replay_speed_timer = bui.AppTimer(
|
||||
0.25, bui.WeakCall(self._change_replay_speed, 0), repeat=True
|
||||
)
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
h - b_size - b_buffer_1,
|
||||
v - b_size - b_buffer_2 + v_offs,
|
||||
),
|
||||
button_type='square',
|
||||
size=(b_size, b_size),
|
||||
label='',
|
||||
autoselect=True,
|
||||
on_activate_call=bui.Call(self._change_replay_speed, -1),
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
draw_controller=btn,
|
||||
text='-',
|
||||
position=(
|
||||
h - b_size * 0.5 - b_buffer_1,
|
||||
v - b_size * 0.5 - b_buffer_2 + 5 * t_scale + v_offs,
|
||||
),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
size=(0, 0),
|
||||
scale=3.0 * t_scale,
|
||||
)
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h + b_buffer_1, v - b_size - b_buffer_2 + v_offs),
|
||||
button_type='square',
|
||||
size=(b_size, b_size),
|
||||
label='',
|
||||
autoselect=True,
|
||||
on_activate_call=bui.Call(self._change_replay_speed, 1),
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
draw_controller=btn,
|
||||
text='+',
|
||||
position=(
|
||||
h + b_size * 0.5 + b_buffer_1,
|
||||
v - b_size * 0.5 - b_buffer_2 + 5 * t_scale + v_offs,
|
||||
),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
size=(0, 0),
|
||||
scale=3.0 * t_scale,
|
||||
)
|
||||
self._pause_resume_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - b_size * 0.5, v - b_size - b_buffer_2 + v_offs),
|
||||
button_type='square',
|
||||
size=(b_size, b_size),
|
||||
label=bui.charstr(
|
||||
bui.SpecialChar.PLAY_BUTTON
|
||||
if bs.is_replay_paused()
|
||||
else bui.SpecialChar.PAUSE_BUTTON
|
||||
),
|
||||
autoselect=True,
|
||||
on_activate_call=bui.Call(self._pause_or_resume_replay),
|
||||
)
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
h - b_size * 1.5 - b_buffer_1 * 2,
|
||||
v - b_size - b_buffer_2 + v_offs,
|
||||
),
|
||||
button_type='square',
|
||||
size=(b_size, b_size),
|
||||
label='',
|
||||
autoselect=True,
|
||||
on_activate_call=bui.WeakCall(self._rewind_replay),
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
draw_controller=btn,
|
||||
# text='<<',
|
||||
text=bui.charstr(bui.SpecialChar.REWIND_BUTTON),
|
||||
position=(
|
||||
h - b_size - b_buffer_1 * 2,
|
||||
v - b_size * 0.5 - b_buffer_2 + 5 * t_scale + v_offs,
|
||||
),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
size=(0, 0),
|
||||
scale=2.0 * t_scale,
|
||||
)
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
h + b_size * 0.5 + b_buffer_1 * 2,
|
||||
v - b_size - b_buffer_2 + v_offs,
|
||||
),
|
||||
button_type='square',
|
||||
size=(b_size, b_size),
|
||||
label='',
|
||||
autoselect=True,
|
||||
on_activate_call=bui.WeakCall(self._forward_replay),
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
draw_controller=btn,
|
||||
# text='>>',
|
||||
text=bui.charstr(bui.SpecialChar.FAST_FORWARD_BUTTON),
|
||||
position=(
|
||||
h + b_size + b_buffer_1 * 2,
|
||||
v - b_size * 0.5 - b_buffer_2 + 5 * t_scale + v_offs,
|
||||
),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
size=(0, 0),
|
||||
scale=2.0 * t_scale,
|
||||
)
|
||||
|
||||
def _rewind_replay(self) -> None:
|
||||
bs.seek_replay(-2 * pow(2, bs.get_replay_speed_exponent()))
|
||||
|
||||
def _forward_replay(self) -> None:
|
||||
bs.seek_replay(2 * pow(2, bs.get_replay_speed_exponent()))
|
||||
|
||||
def _refresh_in_game(
|
||||
self, positions: list[tuple[float, float, float]]
|
||||
) -> tuple[float, float, float]:
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
assert bui.app.classic is not None
|
||||
custom_menu_entries: list[dict[str, Any]] = []
|
||||
session = bs.get_foreground_host_session()
|
||||
if session is not None:
|
||||
try:
|
||||
custom_menu_entries = session.get_custom_menu_entries()
|
||||
for cme in custom_menu_entries:
|
||||
cme_any: Any = cme # Type check may not hold true.
|
||||
if (
|
||||
not isinstance(cme_any, dict)
|
||||
or 'label' not in cme
|
||||
or not isinstance(cme['label'], (str, bui.Lstr))
|
||||
or 'call' not in cme
|
||||
or not callable(cme['call'])
|
||||
):
|
||||
raise ValueError(
|
||||
'invalid custom menu entry: ' + str(cme)
|
||||
)
|
||||
except Exception:
|
||||
custom_menu_entries = []
|
||||
logging.exception(
|
||||
'Error getting custom menu entries for %s.', session
|
||||
)
|
||||
self._width = 250.0
|
||||
self._height = 250.0 if self._input_player else 180.0
|
||||
if (self._is_demo or self._is_arcade) and self._input_player:
|
||||
self._height -= 40
|
||||
# if not self._have_settings_button:
|
||||
self._height -= 50
|
||||
if self._connected_to_remote_player:
|
||||
# In this case we have a leave *and* a disconnect button.
|
||||
self._height += 50
|
||||
self._height += 50 * (len(custom_menu_entries))
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
size=(self._width, self._height),
|
||||
scale=(
|
||||
2.15
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
)
|
||||
h = 125.0
|
||||
v = self._height - 80.0 if self._input_player else self._height - 60
|
||||
h_offset = 0
|
||||
d_h_offset = 0
|
||||
v_offset = -50
|
||||
for _i in range(6 + len(custom_menu_entries)):
|
||||
positions.append((h, v, 1.0))
|
||||
v += v_offset
|
||||
h += h_offset
|
||||
h_offset += d_h_offset
|
||||
# self._play_button = None
|
||||
bui.app.classic.pause()
|
||||
|
||||
# Player name if applicable.
|
||||
if self._input_player:
|
||||
player_name = self._input_player.getname()
|
||||
h, v, scale = positions[self._p_index]
|
||||
v += 35
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width / 2, v),
|
||||
size=(self._button_width, self._button_height),
|
||||
color=(1, 1, 1, 0.5),
|
||||
scale=0.7,
|
||||
h_align='center',
|
||||
text=bui.Lstr(value=player_name),
|
||||
)
|
||||
else:
|
||||
player_name = ''
|
||||
h, v, scale = positions[self._p_index]
|
||||
self._p_index += 1
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width / 2, v),
|
||||
size=(self._button_width, self._button_height),
|
||||
scale=scale,
|
||||
label=bui.Lstr(resource=f'{self._r}.resumeText'),
|
||||
autoselect=self._use_autoselect,
|
||||
on_activate_call=self._resume,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
# Add any custom options defined by the current game.
|
||||
for entry in custom_menu_entries:
|
||||
h, v, scale = positions[self._p_index]
|
||||
self._p_index += 1
|
||||
|
||||
# Ask the entry whether we should resume when we call
|
||||
# it (defaults to true).
|
||||
resume = bool(entry.get('resume_on_call', True))
|
||||
|
||||
if resume:
|
||||
call = bui.Call(self._resume_and_call, entry['call'])
|
||||
else:
|
||||
call = bui.Call(entry['call'], bui.WeakCall(self._resume))
|
||||
|
||||
bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width / 2, v),
|
||||
size=(self._button_width, self._button_height),
|
||||
scale=scale,
|
||||
on_activate_call=call,
|
||||
label=entry['label'],
|
||||
autoselect=self._use_autoselect,
|
||||
)
|
||||
|
||||
# Add a 'leave' button if the menu-owner has a player.
|
||||
if (self._input_player or self._connected_to_remote_player) and not (
|
||||
self._is_demo or self._is_arcade
|
||||
):
|
||||
h, v, scale = positions[self._p_index]
|
||||
self._p_index += 1
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h - self._button_width / 2, v),
|
||||
size=(self._button_width, self._button_height),
|
||||
scale=scale,
|
||||
on_activate_call=self._leave,
|
||||
label='',
|
||||
autoselect=self._use_autoselect,
|
||||
)
|
||||
|
||||
if (
|
||||
player_name != ''
|
||||
and player_name[0] != '<'
|
||||
and player_name[-1] != '>'
|
||||
):
|
||||
txt = bui.Lstr(
|
||||
resource=f'{self._r}.justPlayerText',
|
||||
subs=[('${NAME}', player_name)],
|
||||
)
|
||||
else:
|
||||
txt = bui.Lstr(value=player_name)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
h,
|
||||
v
|
||||
+ self._button_height
|
||||
* (0.64 if player_name != '' else 0.5),
|
||||
),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource=f'{self._r}.leaveGameText'),
|
||||
scale=(0.83 if player_name != '' else 1.0),
|
||||
color=(0.75, 1.0, 0.7),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
draw_controller=btn,
|
||||
maxwidth=self._button_width * 0.9,
|
||||
)
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(h, v + self._button_height * 0.27),
|
||||
size=(0, 0),
|
||||
text=txt,
|
||||
color=(0.75, 1.0, 0.7),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
draw_controller=btn,
|
||||
scale=0.45,
|
||||
maxwidth=self._button_width * 0.9,
|
||||
)
|
||||
return h, v, scale
|
||||
|
||||
def _change_replay_speed(self, offs: int) -> None:
|
||||
if not self._replay_speed_text:
|
||||
if bui.do_once():
|
||||
print('_change_replay_speed called without widget')
|
||||
return
|
||||
bs.set_replay_speed_exponent(bs.get_replay_speed_exponent() + offs)
|
||||
actual_speed = pow(2.0, bs.get_replay_speed_exponent())
|
||||
bui.textwidget(
|
||||
edit=self._replay_speed_text,
|
||||
text=bui.Lstr(
|
||||
resource='watchWindow.playbackSpeedText',
|
||||
subs=[('${SPEED}', str(actual_speed))],
|
||||
),
|
||||
)
|
||||
|
||||
def _pause_or_resume_replay(self) -> None:
|
||||
if bs.is_replay_paused():
|
||||
bs.resume_replay()
|
||||
bui.buttonwidget(
|
||||
edit=self._pause_resume_button,
|
||||
label=bui.charstr(bui.SpecialChar.PAUSE_BUTTON),
|
||||
)
|
||||
else:
|
||||
bs.pause_replay()
|
||||
bui.buttonwidget(
|
||||
edit=self._pause_resume_button,
|
||||
label=bui.charstr(bui.SpecialChar.PLAY_BUTTON),
|
||||
)
|
||||
|
||||
def _is_benchmark(self) -> bool:
|
||||
session = bs.get_foreground_host_session()
|
||||
return getattr(session, 'benchmark_type', None) == 'cpu' or (
|
||||
bui.app.classic is not None
|
||||
and bui.app.classic.stress_test_update_timer is not None
|
||||
)
|
||||
|
||||
def _confirm_end_game(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
# FIXME: Currently we crash calling this on client-sessions.
|
||||
|
||||
# Select cancel by default; this occasionally gets called by accident
|
||||
# in a fit of button mashing and this will help reduce damage.
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource=f'{self._r}.exitToMenuText'),
|
||||
self._end_game,
|
||||
cancel_is_selected=True,
|
||||
)
|
||||
|
||||
def _confirm_end_test(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
# Select cancel by default; this occasionally gets called by accident
|
||||
# in a fit of button mashing and this will help reduce damage.
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource=f'{self._r}.exitToMenuText'),
|
||||
self._end_game,
|
||||
cancel_is_selected=True,
|
||||
)
|
||||
|
||||
def _confirm_end_replay(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
# Select cancel by default; this occasionally gets called by accident
|
||||
# in a fit of button mashing and this will help reduce damage.
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource=f'{self._r}.exitToMenuText'),
|
||||
self._end_game,
|
||||
cancel_is_selected=True,
|
||||
)
|
||||
|
||||
def _confirm_leave_party(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
# Select cancel by default; this occasionally gets called by accident
|
||||
# in a fit of button mashing and this will help reduce damage.
|
||||
ConfirmWindow(
|
||||
bui.Lstr(resource=f'{self._r}.leavePartyConfirmText'),
|
||||
self._leave_party,
|
||||
cancel_is_selected=True,
|
||||
)
|
||||
|
||||
def _leave_party(self) -> None:
|
||||
bs.disconnect_from_host()
|
||||
|
||||
def _end_game(self) -> None:
|
||||
assert bui.app.classic is not None
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
bui.app.classic.return_to_main_menu_session_gracefully(reset_ui=False)
|
||||
|
||||
def _leave(self) -> None:
|
||||
if self._input_player:
|
||||
self._input_player.remove_from_game()
|
||||
elif self._connected_to_remote_player:
|
||||
if self._input_device:
|
||||
self._input_device.detach_from_player()
|
||||
self._resume()
|
||||
|
||||
def _resume_and_call(self, call: Callable[[], Any]) -> None:
|
||||
self._resume()
|
||||
call()
|
||||
|
||||
def _resume(self) -> None:
|
||||
classic = bui.app.classic
|
||||
|
||||
assert classic is not None
|
||||
classic.resume()
|
||||
|
||||
bui.app.ui_v1.clear_main_window()
|
||||
|
||||
# If there's callbacks waiting for us to resume, call them.
|
||||
for call in classic.main_menu_resume_callbacks:
|
||||
try:
|
||||
call()
|
||||
except Exception:
|
||||
logging.exception('Error in classic resume callback.')
|
||||
|
||||
classic.main_menu_resume_callbacks.clear()
|
||||
127
src/assets/ba_data/python/bauiv1lib/inventory.py
Normal file
127
src/assets/ba_data/python/bauiv1lib/inventory.py
Normal file
@ -0,0 +1,127 @@
|
||||
# Released under the MIT License. See LICENSE for details.
|
||||
#
|
||||
"""Provides help related ui."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class InventoryWindow(bui.MainWindow):
|
||||
"""Shows what you got."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
|
||||
bui.set_analytics_screen('Help Window')
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 1050 if uiscale is bui.UIScale.SMALL else 750
|
||||
height = (
|
||||
460
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 530 if uiscale is bui.UIScale.MEDIUM else 600
|
||||
)
|
||||
x_offs = 70 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.55
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.15 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -24)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (0, 15) if uiscale is bui.UIScale.MEDIUM else (0, 0)
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, height - (50 if uiscale is bui.UIScale.SMALL else 45)),
|
||||
size=(width, 25),
|
||||
text='INVENTORY',
|
||||
color=bui.app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(x_offs + 50, height - 55),
|
||||
size=(60, 55),
|
||||
scale=0.8,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
extra_touch_border_scale=2.0,
|
||||
autoselect=True,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, height - 120),
|
||||
size=(width, 25),
|
||||
text='(under construction)',
|
||||
scale=0.7,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
button_width = 300
|
||||
self._player_profiles_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=((width - button_width) * 0.5, height - 200),
|
||||
autoselect=True,
|
||||
size=(button_width, 60),
|
||||
label=bui.Lstr(resource='playerProfilesWindow.titleText'),
|
||||
color=(0.55, 0.5, 0.6),
|
||||
icon=bui.gettexture('cuteSpaz'),
|
||||
textcolor=(0.75, 0.7, 0.8),
|
||||
on_activate_call=self._player_profiles_press,
|
||||
)
|
||||
|
||||
def _player_profiles_press(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self.main_window_replace(
|
||||
ProfileBrowserWindow(origin_widget=self._player_profiles_button)
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
@ -8,10 +8,14 @@ import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class KioskWindow(bui.Window):
|
||||
class KioskWindow(bui.MainWindow):
|
||||
"""Kiosk mode window."""
|
||||
|
||||
def __init__(self, transition: str = 'in_right'):
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-locals, too-many-statements
|
||||
from bauiv1lib.confirm import QuitWindow
|
||||
|
||||
@ -26,11 +30,13 @@ class KioskWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition=transition,
|
||||
# transition=transition,
|
||||
on_cancel_call=_do_cancel,
|
||||
background=False,
|
||||
stack_offset=(0, -130),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._r = 'kioskWindow'
|
||||
@ -501,6 +507,7 @@ class KioskWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
def _do_full_menu(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
@ -512,6 +519,4 @@ class KioskWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
bui.app.classic.did_menu_intro = True # prevent delayed transition-in
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow().get_root_widget(), from_window=self._root_widget
|
||||
)
|
||||
bui.app.ui_v1.set_main_window(MainMenuWindow(), from_window=self)
|
||||
|
||||
@ -16,14 +16,14 @@ if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class LeagueRankWindow(bui.Window):
|
||||
class LeagueRankWindow(bui.MainWindow):
|
||||
"""Window for showing league rank."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
modal: bool = False,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
modal: bool = False,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
plus = bui.app.plus
|
||||
@ -46,22 +46,18 @@ class LeagueRankWindow(bui.Window):
|
||||
self._to_ranked_text: bui.Widget | None = None
|
||||
self._trophy_counts_reset_text: bui.Widget | None = None
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
# Need to handle transitioning out ourself for modal case
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 1320 if uiscale is bui.UIScale.SMALL else 1120
|
||||
self._width = 1490 if uiscale is bui.UIScale.SMALL else 1120
|
||||
x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
657
|
||||
660
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 710 if uiscale is bui.UIScale.MEDIUM else 800
|
||||
)
|
||||
@ -69,6 +65,8 @@ class LeagueRankWindow(bui.Window):
|
||||
self._rdict = bui.app.lang.get_resource(self._r)
|
||||
top_extra = 20 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
self._xoffs = 80.0 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
self._league_url_arg = ''
|
||||
|
||||
self._is_current_season = False
|
||||
@ -78,37 +76,62 @@ class LeagueRankWindow(bui.Window):
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
stack_offset=(
|
||||
(0, -15)
|
||||
(0, 0)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (0, 10) if uiscale is bui.UIScale.MEDIUM else (0, 0)
|
||||
),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
1.2
|
||||
1.08
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 0.93 if uiscale is bui.UIScale.MEDIUM else 0.8
|
||||
),
|
||||
)
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(
|
||||
75 + x_inset,
|
||||
self._height - 87 - (4 if uiscale is bui.UIScale.SMALL else 0),
|
||||
),
|
||||
size=(120, 60),
|
||||
scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='doneText' if self._modal else 'backText'),
|
||||
button_type=None if self._modal else 'back',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
)
|
||||
else:
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(75 + x_inset, self._height - 87),
|
||||
size=(120, 60),
|
||||
scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(
|
||||
resource='doneText' if self._modal else 'backText'
|
||||
),
|
||||
button_type=None if self._modal else 'back',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
position=(75 + x_inset, self._height - 87),
|
||||
size=(60, 55),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
cancel_button=self._back_button,
|
||||
selected_child=self._back_button,
|
||||
)
|
||||
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 56),
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (66 if uiscale is bui.UIScale.SMALL else 56),
|
||||
),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(
|
||||
resource='league.leagueRankText',
|
||||
@ -121,17 +144,6 @@ class LeagueRankWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
position=(
|
||||
75 + x_inset,
|
||||
self._height - 87 - (2 if uiscale is bui.UIScale.SMALL else 0),
|
||||
),
|
||||
size=(60, 55),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
self._scroll_width = self._width - (130 + 2 * x_inset)
|
||||
self._scroll_height = self._height - 160
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
@ -143,11 +155,6 @@ class LeagueRankWindow(bui.Window):
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
bui.containerwidget(edit=self._scrollwidget, claims_left_right=True)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
cancel_button=self._back_button,
|
||||
selected_child=self._back_button,
|
||||
)
|
||||
|
||||
self._last_power_ranking_query_time: float | None = None
|
||||
self._doing_power_ranking_query = False
|
||||
@ -374,7 +381,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 106),
|
||||
position=(self._xoffs + h2 - 60, v2 + 106),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -388,7 +395,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._power_ranking_achievements_button = bui.buttonwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 10),
|
||||
position=(self._xoffs + h2 - 60, v2 + 10),
|
||||
size=(200, 80),
|
||||
icon=bui.gettexture('achievementsIcon'),
|
||||
autoselect=True,
|
||||
@ -402,7 +409,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._power_ranking_achievement_total_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + h_offs_tally, v2 + 45),
|
||||
position=(self._xoffs + h2 + h_offs_tally, v2 + 45),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -418,7 +425,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._power_ranking_trophies_button = bui.buttonwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 10),
|
||||
position=(self._xoffs + h2 - 60, v2 + 10),
|
||||
size=(200, 80),
|
||||
icon=bui.gettexture('medalSilver'),
|
||||
autoselect=True,
|
||||
@ -430,7 +437,7 @@ class LeagueRankWindow(bui.Window):
|
||||
)
|
||||
self._power_ranking_trophies_total_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + h_offs_tally, v2 + 45),
|
||||
position=(self._xoffs + h2 + h_offs_tally, v2 + 45),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -446,7 +453,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 86),
|
||||
position=(self._xoffs + h2 - 60, v2 + 86),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -462,7 +469,7 @@ class LeagueRankWindow(bui.Window):
|
||||
if plus.get_v1_account_misc_read_val('act', False):
|
||||
self._activity_mult_button = bui.buttonwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 10),
|
||||
position=(self._xoffs + h2 - 60, v2 + 10),
|
||||
size=(200, 60),
|
||||
icon=bui.gettexture('heart'),
|
||||
icon_color=(0.5, 0, 0.5),
|
||||
@ -476,7 +483,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._activity_mult_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + h_offs_tally, v2 + 40),
|
||||
position=(self._xoffs + h2 + h_offs_tally, v2 + 40),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -493,7 +500,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._pro_mult_button = bui.buttonwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 60, v2 + 10),
|
||||
position=(self._xoffs + h2 - 60, v2 + 10),
|
||||
size=(200, 60),
|
||||
icon=bui.gettexture('logo'),
|
||||
icon_color=(0.3, 0, 0.3),
|
||||
@ -510,7 +517,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._pro_mult_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + h_offs_tally, v2 + 40),
|
||||
position=(self._xoffs + h2 + h_offs_tally, v2 + 40),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -526,7 +533,7 @@ class LeagueRankWindow(bui.Window):
|
||||
v2 -= spc
|
||||
bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + h_offs_tally - 10 - 40, v2 + 35),
|
||||
position=(self._xoffs + h2 + h_offs_tally - 10 - 40, v2 + 35),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -539,7 +546,7 @@ class LeagueRankWindow(bui.Window):
|
||||
)
|
||||
self._power_ranking_total_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + h_offs_tally - 40, v2 + 35),
|
||||
position=(self._xoffs + h2 + h_offs_tally - 40, v2 + 35),
|
||||
size=(0, 0),
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
@ -553,7 +560,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._season_show_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(390 - 15, v - 20),
|
||||
position=(self._xoffs + 390 - 15, v - 20),
|
||||
size=(0, 0),
|
||||
color=(0.6, 0.6, 0.7),
|
||||
maxwidth=200,
|
||||
@ -567,7 +574,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._league_title_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 97),
|
||||
position=(self._xoffs + 470, v - 97),
|
||||
size=(0, 0),
|
||||
color=(0.6, 0.6, 0.7),
|
||||
maxwidth=230,
|
||||
@ -583,7 +590,7 @@ class LeagueRankWindow(bui.Window):
|
||||
self._league_text_maxwidth = 210
|
||||
self._league_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 140),
|
||||
position=(self._xoffs + 470, v - 140),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 1),
|
||||
maxwidth=self._league_text_maxwidth,
|
||||
@ -597,7 +604,7 @@ class LeagueRankWindow(bui.Window):
|
||||
self._league_number_base_pos = (470, v - 140)
|
||||
self._league_number_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 140),
|
||||
position=(self._xoffs + 470, v - 140),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 1),
|
||||
maxwidth=100,
|
||||
@ -611,7 +618,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._your_power_ranking_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 142 - 70),
|
||||
position=(self._xoffs + 470, v - 142 - 70),
|
||||
size=(0, 0),
|
||||
color=(0.6, 0.6, 0.7),
|
||||
maxwidth=230,
|
||||
@ -625,7 +632,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._to_ranked_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 250 - 70),
|
||||
position=(self._xoffs + 470, v - 250 - 70),
|
||||
size=(0, 0),
|
||||
color=(0.6, 0.6, 0.7),
|
||||
maxwidth=230,
|
||||
@ -639,7 +646,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._power_ranking_rank_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(473, v - 210 - 70),
|
||||
position=(self._xoffs + 473, v - 210 - 70),
|
||||
size=(0, 0),
|
||||
big=False,
|
||||
text='-',
|
||||
@ -650,7 +657,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
self._season_ends_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 380),
|
||||
position=(self._xoffs + 470, v - 380),
|
||||
size=(0, 0),
|
||||
color=(0.6, 0.6, 0.6),
|
||||
maxwidth=230,
|
||||
@ -663,7 +670,7 @@ class LeagueRankWindow(bui.Window):
|
||||
)
|
||||
self._trophy_counts_reset_text = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(470, v - 410),
|
||||
position=(self._xoffs + 470, v - 410),
|
||||
size=(0, 0),
|
||||
color=(0.5, 0.5, 0.5),
|
||||
maxwidth=230,
|
||||
@ -685,7 +692,7 @@ class LeagueRankWindow(bui.Window):
|
||||
self._see_more_button = bui.buttonwidget(
|
||||
parent=w_parent,
|
||||
label=self._rdict.seeMoreText,
|
||||
position=(h, v),
|
||||
position=(self._xoffs + h, v),
|
||||
color=(0.5, 0.5, 0.6),
|
||||
textcolor=(0.7, 0.7, 0.8),
|
||||
size=(230, 60),
|
||||
@ -732,6 +739,7 @@ class LeagueRankWindow(bui.Window):
|
||||
if not self._root_widget:
|
||||
return
|
||||
plus = bui.app.plus
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
assert plus is not None
|
||||
assert bui.app.classic is not None
|
||||
accounts = bui.app.classic.accounts
|
||||
@ -825,7 +833,7 @@ class LeagueRankWindow(bui.Window):
|
||||
assert self._subcontainer
|
||||
self._season_popup_menu = PopupMenu(
|
||||
parent=self._subcontainer,
|
||||
position=(390, v - 45),
|
||||
position=(self._xoffs + 390, v - 45),
|
||||
width=150,
|
||||
button_size=(200, 50),
|
||||
choices=season_choices,
|
||||
@ -843,11 +851,12 @@ class LeagueRankWindow(bui.Window):
|
||||
edit=self._season_popup_menu.get_button(),
|
||||
up_widget=self._back_button,
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._back_button,
|
||||
down_widget=self._power_ranking_achievements_button,
|
||||
right_widget=self._season_popup_menu.get_button(),
|
||||
)
|
||||
if uiscale is not bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=self._back_button,
|
||||
down_widget=self._power_ranking_achievements_button,
|
||||
right_widget=self._season_popup_menu.get_button(),
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._league_title_text,
|
||||
@ -928,7 +937,10 @@ class LeagueRankWindow(bui.Window):
|
||||
text=lnum,
|
||||
color=lcolor,
|
||||
position=(
|
||||
self._league_number_base_pos[0] + l_text_width * 0.5 + 8,
|
||||
self._xoffs
|
||||
+ self._league_number_base_pos[0]
|
||||
+ l_text_width * 0.5
|
||||
+ 8,
|
||||
self._league_number_base_pos[1] + 10,
|
||||
),
|
||||
)
|
||||
@ -957,7 +969,7 @@ class LeagueRankWindow(bui.Window):
|
||||
|
||||
bui.textwidget(
|
||||
edit=self._power_ranking_rank_text,
|
||||
position=(473, v - 70 - (170 if do_percent else 220)),
|
||||
position=(self._xoffs + 473, v - 70 - (170 if do_percent else 220)),
|
||||
text=status_text,
|
||||
big=(in_top or do_percent),
|
||||
scale=(
|
||||
@ -1080,7 +1092,7 @@ class LeagueRankWindow(bui.Window):
|
||||
self._power_ranking_score_widgets.append(
|
||||
bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 - 20, v2),
|
||||
position=(self._xoffs + h2 - 20, v2),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 1) if is_us else (0.6, 0.6, 0.7),
|
||||
maxwidth=40,
|
||||
@ -1095,7 +1107,7 @@ class LeagueRankWindow(bui.Window):
|
||||
self._power_ranking_score_widgets.append(
|
||||
bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + 20, v2),
|
||||
position=(self._xoffs + h2 + 20, v2),
|
||||
size=(0, 0),
|
||||
color=(1, 1, 1) if is_us else tally_color,
|
||||
maxwidth=60,
|
||||
@ -1109,7 +1121,7 @@ class LeagueRankWindow(bui.Window):
|
||||
)
|
||||
txt = bui.textwidget(
|
||||
parent=w_parent,
|
||||
position=(h2 + 60, v2 - (28 * 0.5) / 0.9),
|
||||
position=(self._xoffs + h2 + 60, v2 - (28 * 0.5) / 0.9),
|
||||
size=(210 / 0.9, 28),
|
||||
color=(1, 1, 1) if is_us else (0.6, 0.6, 0.6),
|
||||
maxwidth=210,
|
||||
@ -1155,19 +1167,15 @@ class LeagueRankWindow(bui.Window):
|
||||
pass
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
if self._modal:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
else:
|
||||
self.main_window_back()
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -48,15 +48,15 @@ class PartyWindow(bui.Window):
|
||||
on_outside_click_call=self.close_with_sound,
|
||||
scale_origin_stack_offset=origin,
|
||||
scale=(
|
||||
2.0
|
||||
1.6
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 0.9
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -10)
|
||||
(200, -10)
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else (
|
||||
(240, 0) if uiscale is bui.UIScale.MEDIUM else (330, 20)
|
||||
(260, 0) if uiscale is bui.UIScale.MEDIUM else (370, 60)
|
||||
)
|
||||
),
|
||||
)
|
||||
|
||||
@ -223,7 +223,6 @@ class PartyQueueWindow(bui.Window):
|
||||
|
||||
def __init__(self, queue_id: str, address: str, port: int):
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.have_party_queue_window = True
|
||||
self._address = address
|
||||
self._port = port
|
||||
self._queue_id = queue_id
|
||||
@ -329,8 +328,6 @@ class PartyQueueWindow(bui.Window):
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.have_party_queue_window = False
|
||||
plus.add_v1_account_transaction(
|
||||
{'type': 'PARTY_QUEUE_REMOVE', 'q': self._queue_id}
|
||||
)
|
||||
@ -564,7 +561,8 @@ class PartyQueueWindow(bui.Window):
|
||||
def on_boost_press(self) -> None:
|
||||
"""Boost was pressed."""
|
||||
from bauiv1lib import account
|
||||
from bauiv1lib import gettickets
|
||||
|
||||
# from bauiv1lib import gettickets
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -575,7 +573,7 @@ class PartyQueueWindow(bui.Window):
|
||||
|
||||
if plus.get_v1_account_ticket_count() < self._boost_tickets:
|
||||
bui.getsound('error').play()
|
||||
gettickets.show_get_tickets_prompt()
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
return
|
||||
|
||||
bui.getsound('laserReverse').play()
|
||||
|
||||
@ -5,31 +5,35 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class PlayWindow(bui.Window):
|
||||
class PlayWindow(bui.MainWindow):
|
||||
"""Window for selecting overall play type."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
import threading
|
||||
|
||||
# Preload some modules we use in a background thread so we won't
|
||||
# have a visual hitch when the user taps them.
|
||||
threading.Thread(target=self._preload_modules).start()
|
||||
bui.app.threadpool_submit_no_wait(self._preload_modules)
|
||||
|
||||
# We can currently be used either for main menu duty or for selecting
|
||||
# playlists (should make this more elegant/general).
|
||||
assert bui.app.classic is not None
|
||||
self._is_main_menu = not bui.app.ui_v1.selecting_private_party_playlist
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
|
||||
# We can currently be used either for main window duty or
|
||||
# modally for selecting playlists. Ideally we should clean
|
||||
# things up and make playlist selection go through the
|
||||
# main-window mechanism.
|
||||
self._is_main_menu = not classic.selecting_private_party_playlist
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 1100 if uiscale is bui.UIScale.SMALL else 800
|
||||
@ -37,30 +41,31 @@ class PlayWindow(bui.Window):
|
||||
height = 550
|
||||
button_width = 400
|
||||
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
|
||||
# Need to store this ourself since we can function as a
|
||||
# non-main window.
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'playWindow'
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_full',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
1.6
|
||||
1.35
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 0.9 if uiscale is bui.UIScale.MEDIUM else 0.8
|
||||
),
|
||||
stack_offset=(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0),
|
||||
)
|
||||
stack_offset=(
|
||||
(0, 20) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
self._back_button = back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
@ -101,18 +106,14 @@ class PlayWindow(bui.Window):
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.textwidget(edit=txt, text='')
|
||||
|
||||
v = height - (110 if self._is_main_menu else 90)
|
||||
v -= 100
|
||||
clr = (0.6, 0.7, 0.6, 1.0)
|
||||
v -= 280 if self._is_main_menu else 180
|
||||
v += (
|
||||
30
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL
|
||||
else 0
|
||||
)
|
||||
v += 30 if uiscale is bui.UIScale.SMALL else 0
|
||||
hoffs = x_offs + 80 if self._is_main_menu else x_offs - 100
|
||||
scl = 1.13 if self._is_main_menu else 0.68
|
||||
|
||||
@ -153,7 +154,7 @@ class PlayWindow(bui.Window):
|
||||
on_activate_call=self._coop,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
@ -256,12 +257,11 @@ class PlayWindow(bui.Window):
|
||||
on_activate_call=self._team_tourney,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
up_widget=bui.get_special_widget('tickets_plus_button'),
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
up_widget=bui.get_special_widget('get_tokens_button'),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
xxx = -14
|
||||
self._draw_dude(
|
||||
@ -489,11 +489,12 @@ class PlayWindow(bui.Window):
|
||||
color=clr,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
back_button.delete()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
on_cancel_call=self._back,
|
||||
# cancel_button=bui.get_special_widget('back_button'),
|
||||
selected_child=(
|
||||
self._coop_button
|
||||
if self._is_main_menu
|
||||
@ -514,7 +515,20 @@ class PlayWindow(bui.Window):
|
||||
|
||||
self._restore_state()
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
@ -526,30 +540,22 @@ class PlayWindow(bui.Window):
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# no-op if we're not currently in control.
|
||||
if not self.can_change_main_window():
|
||||
return
|
||||
|
||||
if self._is_main_menu:
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
self._save_state()
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
self.main_window_back()
|
||||
else:
|
||||
from bauiv1lib.gather import GatherWindow
|
||||
|
||||
self._save_state()
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
|
||||
self._save_state()
|
||||
bui.app.ui_v1.set_main_window(
|
||||
GatherWindow(transition='in_left'),
|
||||
from_window=self,
|
||||
is_back=True,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
@ -560,8 +566,8 @@ class PlayWindow(bui.Window):
|
||||
from bauiv1lib.account import show_sign_in_prompt
|
||||
from bauiv1lib.coop.browser import CoopBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# no-op if we're not currently in control.
|
||||
if not self.can_change_main_window():
|
||||
return
|
||||
|
||||
plus = bui.app.plus
|
||||
@ -573,48 +579,43 @@ class PlayWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
CoopBrowserWindow(
|
||||
origin_widget=self._coop_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
CoopBrowserWindow(origin_widget=self._coop_button), from_window=self
|
||||
)
|
||||
|
||||
def _team_tourney(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.browser import PlaylistBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# no-op if we're not currently in control.
|
||||
if not self.can_change_main_window():
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
|
||||
self.main_window_replace(
|
||||
PlaylistBrowserWindow(
|
||||
origin_widget=self._teams_button, sessiontype=bs.DualTeamSession
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
)
|
||||
|
||||
def _free_for_all(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist.browser import PlaylistBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# no-op if we're not currently in control.
|
||||
if not self.can_change_main_window():
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistBrowserWindow(
|
||||
origin_widget=self._free_for_all_button,
|
||||
sessiontype=bs.FreeForAllSession,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _draw_dude(
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
@ -13,13 +13,14 @@ if TYPE_CHECKING:
|
||||
from bauiv1lib.playlist.editcontroller import PlaylistEditController
|
||||
|
||||
|
||||
class PlaylistAddGameWindow(bui.Window):
|
||||
class PlaylistAddGameWindow(bui.MainWindow):
|
||||
"""Window for selecting a game type to add to a playlist."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
editcontroller: PlaylistEditController,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
self._editcontroller = editcontroller
|
||||
self._r = 'addGameWindow'
|
||||
@ -38,27 +39,32 @@ class PlaylistAddGameWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
scale=(
|
||||
2.17
|
||||
1.95
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(0, 1) if uiscale is bui.UIScale.SMALL else (0, 0),
|
||||
)
|
||||
toolbar_visibility='menu_minimal',
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(58 + x_inset, self._height - 53),
|
||||
size=(165, 70),
|
||||
scale=0.75,
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
autoselect=True,
|
||||
button_type='back',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
else:
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(58 + x_inset, self._height - 53),
|
||||
size=(165, 70),
|
||||
scale=0.75,
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
autoselect=True,
|
||||
button_type='back',
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
self._select_button = select_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width - (172 + x_inset), self._height - 50),
|
||||
@ -70,11 +76,10 @@ class PlaylistAddGameWindow(bui.Window):
|
||||
on_activate_call=self._add,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=select_button,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=select_button,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -130,11 +135,18 @@ class PlaylistAddGameWindow(bui.Window):
|
||||
self._column: bui.Widget | None = None
|
||||
|
||||
v -= 35
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
cancel_button=self._back_button,
|
||||
start_button=select_button,
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget,
|
||||
cancel_button=self._back_button,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, start_button=select_button)
|
||||
|
||||
self._selected_game_type: type[bs.GameActivity] | None = None
|
||||
|
||||
bui.containerwidget(
|
||||
@ -154,6 +166,23 @@ class PlaylistAddGameWindow(bui.Window):
|
||||
# game loading is complete.
|
||||
self._refresh()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Avoid dereferencing self from the lambda or we'll keep
|
||||
# ourself alive indefinitely.
|
||||
editcontroller = self._editcontroller
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
editcontroller=editcontroller,
|
||||
)
|
||||
)
|
||||
|
||||
def _on_game_types_loaded(
|
||||
self, gametypes: list[type[bs.GameActivity]]
|
||||
) -> None:
|
||||
@ -262,5 +291,5 @@ class PlaylistAddGameWindow(bui.Window):
|
||||
),
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
self._editcontroller.add_game_cancelled()
|
||||
# def _back(self) -> None:
|
||||
# self._editcontroller.add_game_cancelled()
|
||||
|
||||
@ -4,15 +4,16 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import copy
|
||||
import math
|
||||
import logging
|
||||
from typing import override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class PlaylistBrowserWindow(bui.Window):
|
||||
class PlaylistBrowserWindow(bui.MainWindow):
|
||||
"""Window for starting teams games."""
|
||||
|
||||
def __init__(
|
||||
@ -21,28 +22,13 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist import PlaylistTypeVars
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
|
||||
# Store state for when we exit the next game.
|
||||
if issubclass(sessiontype, bs.DualTeamSession):
|
||||
bui.app.ui_v1.set_main_menu_location('Team Game Select')
|
||||
bui.set_analytics_screen('Teams Window')
|
||||
elif issubclass(sessiontype, bs.FreeForAllSession):
|
||||
bui.app.ui_v1.set_main_menu_location('Free-for-All Game Select')
|
||||
bui.set_analytics_screen('FreeForAll Window')
|
||||
else:
|
||||
raise TypeError(f'Invalid sessiontype: {sessiontype}.')
|
||||
@ -65,7 +51,7 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
self._width = 1100.0 if uiscale is bui.UIScale.SMALL else 800.0
|
||||
x_inset = 150 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
480
|
||||
440
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 510 if uiscale is bui.UIScale.MEDIUM else 580
|
||||
)
|
||||
@ -75,18 +61,22 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_full',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.69
|
||||
1.83
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.05 if uiscale is bui.UIScale.MEDIUM else 0.9
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -26) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, -56) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button: bui.Widget | None = bui.buttonwidget(
|
||||
@ -102,19 +92,22 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
txt = self._title_text = bui.textwidget(
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 41),
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (32 if uiscale is bui.UIScale.SMALL else 41),
|
||||
),
|
||||
size=(0, 0),
|
||||
text=self._pvars.window_title_name,
|
||||
scale=1.3,
|
||||
scale=(0.8 if uiscale is bui.UIScale.SMALL else 1.3),
|
||||
res_scale=1.5,
|
||||
color=bui.app.ui_v1.heading_color,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars:
|
||||
bui.textwidget(edit=txt, text='')
|
||||
# if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars:
|
||||
# bui.textwidget(edit=txt, text='')
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
@ -124,7 +117,7 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button.delete()
|
||||
self._back_button = None
|
||||
bui.containerwidget(
|
||||
@ -135,9 +128,7 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
scroll_offs = 0
|
||||
self._scroll_width = self._width - (100 + 2 * x_inset)
|
||||
self._scroll_height = self._height - (
|
||||
146
|
||||
if uiscale is bui.UIScale.SMALL and bui.app.ui_v1.use_toolbars
|
||||
else 136
|
||||
146 if uiscale is bui.UIScale.SMALL else 136
|
||||
)
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
parent=self._root_widget,
|
||||
@ -160,6 +151,27 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
1.0, bui.WeakCall(self._update), repeat=True
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Pull things out of self here; if we do it below in the lambda
|
||||
# then we keep self alive.
|
||||
sessiontype = self._sessiontype
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
sessiontype=sessiontype,
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _ensure_standard_playlists_exist(self) -> None:
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -418,23 +430,15 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
position=pos,
|
||||
)
|
||||
|
||||
if (
|
||||
x == 0
|
||||
and bui.app.ui_v1.use_toolbars
|
||||
and uiscale is bui.UIScale.SMALL
|
||||
):
|
||||
if x == 0 and uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
if (
|
||||
x == columns - 1
|
||||
and bui.app.ui_v1.use_toolbars
|
||||
and uiscale is bui.UIScale.SMALL
|
||||
):
|
||||
if x == columns - 1 and uiscale is bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
@ -687,17 +691,17 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistCustomizeBrowserWindow(
|
||||
origin_widget=self._customize_button,
|
||||
sessiontype=self._sessiontype,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _on_back_press(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.play import PlayWindow
|
||||
# from bauiv1lib.play import PlayWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -715,15 +719,16 @@ class PlaylistBrowserWindow(bui.Window):
|
||||
)
|
||||
cfg.commit()
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlayWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
self.main_window_back()
|
||||
|
||||
# self._save_state()
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition=self._transition_out
|
||||
# )
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# PlayWindow(transition='in_left'), from_window=self, is_back=True
|
||||
# )
|
||||
|
||||
def _save_state(self) -> None:
|
||||
try:
|
||||
|
||||
@ -7,7 +7,7 @@ from __future__ import annotations
|
||||
import copy
|
||||
import time
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
@ -15,16 +15,21 @@ import bauiv1 as bui
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
REQUIRE_PRO = False
|
||||
|
||||
class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
# TEMP
|
||||
UNDER_CONSTRUCTION = True
|
||||
|
||||
|
||||
class PlaylistCustomizeBrowserWindow(bui.MainWindow):
|
||||
"""Window for viewing a playlist."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
sessiontype: type[bs.Session],
|
||||
transition: str = 'in_right',
|
||||
select_playlist: str | None = None,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
select_playlist: str | None = None,
|
||||
):
|
||||
# Yes this needs tidying.
|
||||
# pylint: disable=too-many-locals
|
||||
@ -32,22 +37,13 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib import playlist
|
||||
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._sessiontype = sessiontype
|
||||
self._pvars = playlist.PlaylistTypeVars(sessiontype)
|
||||
self._max_playlists = 30
|
||||
self._r = 'gameListWindow'
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 850.0 if uiscale is bui.UIScale.SMALL else 650.0
|
||||
self._width = 970.0 if uiscale is bui.UIScale.SMALL else 650.0
|
||||
x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0
|
||||
self._height = (
|
||||
380.0
|
||||
@ -59,29 +55,47 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
2.05
|
||||
1.83
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button = back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(43 + x_inset, self._height - 60),
|
||||
size=(160, 68),
|
||||
scale=0.77,
|
||||
autoselect=True,
|
||||
text_scale=1.3,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
)
|
||||
self._back_button: bui.Widget | None
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = None
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
)
|
||||
else:
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(43 + x_inset, self._height - 60),
|
||||
size=(160, 68),
|
||||
scale=0.77,
|
||||
autoselect=True,
|
||||
text_scale=1.3,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
)
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -97,13 +111,6 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
v = self._height - 59.0
|
||||
h = 41 + x_inset
|
||||
b_color = (0.6, 0.53, 0.63)
|
||||
@ -261,7 +268,9 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
size=(self._width - (180 + 2 * x_inset), self._scroll_height + 10),
|
||||
highlight=False,
|
||||
)
|
||||
bui.widget(edit=back_button, right_widget=scrollwidget)
|
||||
if self._back_button is not None:
|
||||
bui.widget(edit=self._back_button, right_widget=scrollwidget)
|
||||
|
||||
self._columnwidget = bui.columnwidget(
|
||||
parent=scrollwidget, border=2, margin=0
|
||||
)
|
||||
@ -279,11 +288,7 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
bui.widget(
|
||||
edit=scrollwidget,
|
||||
left_widget=new_button,
|
||||
right_widget=(
|
||||
bui.get_special_widget('party_button')
|
||||
if bui.app.ui_v1.use_toolbars
|
||||
else None
|
||||
),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
# make sure config exists
|
||||
@ -298,8 +303,13 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
|
||||
self._refresh(select_playlist=select_playlist)
|
||||
|
||||
bui.buttonwidget(edit=back_button, on_activate_call=self._back)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=back_button)
|
||||
if self._back_button is not None:
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button, on_activate_call=self._back
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, selected_child=scrollwidget)
|
||||
|
||||
@ -309,15 +319,38 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
)
|
||||
self._update()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Avoid dereferencing self within the lambda or we'll keep
|
||||
# ourself alive indefinitely.
|
||||
stype = self._sessiontype
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
sessiontype=stype,
|
||||
)
|
||||
)
|
||||
|
||||
# @override
|
||||
# def on_main_window_close(self) -> None:
|
||||
# self._save_state()
|
||||
|
||||
def _update(self) -> None:
|
||||
assert bui.app.classic is not None
|
||||
have = bui.app.classic.accounts.have_pro_options()
|
||||
for lock in self._lock_images:
|
||||
bui.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
|
||||
bui.imagewidget(
|
||||
edit=lock, opacity=0.0 if (have or not REQUIRE_PRO) else 1.0
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.playlist import browser
|
||||
# from bauiv1lib.playlist import browser
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -330,16 +363,18 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
)
|
||||
cfg.commit()
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
browser.PlaylistBrowserWindow(
|
||||
transition='in_left', sessiontype=self._sessiontype
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
self.main_window_back()
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition=self._transition_out
|
||||
# )
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# browser.PlaylistBrowserWindow(
|
||||
# transition='in_left', sessiontype=self._sessiontype
|
||||
# ),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _select(self, name: str, index: int) -> None:
|
||||
self._selected_playlist_name = name
|
||||
@ -418,7 +453,14 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
|
||||
# Hitting up from top widget should jump to 'back'
|
||||
if index == 0:
|
||||
bui.widget(edit=txtw, up_widget=self._back_button)
|
||||
bui.widget(
|
||||
edit=txtw,
|
||||
up_widget=(
|
||||
self._back_button
|
||||
if self._back_button is not None
|
||||
else bui.get_special_widget('back_button')
|
||||
),
|
||||
)
|
||||
|
||||
self._playlist_widgets.append(txtw)
|
||||
|
||||
@ -469,8 +511,12 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
from bauiv1lib.playlist.editcontroller import PlaylistEditController
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
|
||||
if UNDER_CONSTRUCTION:
|
||||
bui.screenmessage('UNDER CONSTRUCTION')
|
||||
return
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro_options():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro_options():
|
||||
PurchaseWindow(items=['pro'])
|
||||
return
|
||||
|
||||
@ -500,8 +546,12 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
from bauiv1lib.playlist.editcontroller import PlaylistEditController
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
|
||||
if UNDER_CONSTRUCTION:
|
||||
bui.screenmessage('UNDER CONSTRUCTION')
|
||||
return
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro_options():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro_options():
|
||||
PurchaseWindow(items=['pro'])
|
||||
return
|
||||
if self._selected_playlist_name is None:
|
||||
@ -584,7 +634,7 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
assert plus is not None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro_options():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro_options():
|
||||
PurchaseWindow(items=['pro'])
|
||||
return
|
||||
|
||||
@ -626,7 +676,7 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro_options():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro_options():
|
||||
PurchaseWindow(items=['pro'])
|
||||
return
|
||||
|
||||
@ -666,7 +716,7 @@ class PlaylistCustomizeBrowserWindow(bui.Window):
|
||||
assert plus is not None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if not bui.app.classic.accounts.have_pro_options():
|
||||
if REQUIRE_PRO and not bui.app.classic.accounts.have_pro_options():
|
||||
PurchaseWindow(items=['pro'])
|
||||
return
|
||||
if self._selected_playlist_name is None:
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from typing import TYPE_CHECKING, cast, override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
@ -14,13 +14,14 @@ if TYPE_CHECKING:
|
||||
from bauiv1lib.playlist.editcontroller import PlaylistEditController
|
||||
|
||||
|
||||
class PlaylistEditWindow(bui.Window):
|
||||
class PlaylistEditWindow(bui.MainWindow):
|
||||
"""Window for editing an individual game playlist."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
editcontroller: PlaylistEditController,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
@ -43,16 +44,17 @@ class PlaylistEditWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
scale=(
|
||||
2.0
|
||||
1.8
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -16) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
cancel_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
@ -74,11 +76,10 @@ class PlaylistEditWindow(bui.Window):
|
||||
text_scale=1.2,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
bui.widget(
|
||||
edit=cancel_button,
|
||||
@ -270,31 +271,49 @@ class PlaylistEditWindow(bui.Window):
|
||||
edit=self._root_widget, selected_child=scrollwidget
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
editcontroller = self._editcontroller
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
editcontroller=editcontroller,
|
||||
)
|
||||
)
|
||||
|
||||
def _set_ui_selection(self, selection: str) -> None:
|
||||
self._editcontroller.set_edit_ui_selection(selection)
|
||||
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.playlist.customizebrowser import (
|
||||
PlaylistCustomizeBrowserWindow,
|
||||
)
|
||||
# from bauiv1lib.playlist.customizebrowser import (
|
||||
# PlaylistCustomizeBrowserWindow,
|
||||
# )
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.getsound('powerdown01').play()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistCustomizeBrowserWindow(
|
||||
transition='in_left',
|
||||
sessiontype=self._editcontroller.get_session_type(),
|
||||
select_playlist=(
|
||||
self._editcontroller.get_existing_playlist_name()
|
||||
),
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
self.main_window_back()
|
||||
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# PlaylistCustomizeBrowserWindow(
|
||||
# transition='in_left',
|
||||
# sessiontype=self._editcontroller.get_session_type(),
|
||||
# select_playlist=(
|
||||
# self._editcontroller.get_existing_playlist_name()
|
||||
# ),
|
||||
# ),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _add(self) -> None:
|
||||
# Store list name then tell the session to perform an add.
|
||||
@ -379,13 +398,14 @@ class PlaylistEditWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
bui.getsound('gunCocking').play()
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistCustomizeBrowserWindow(
|
||||
transition='in_left',
|
||||
sessiontype=self._editcontroller.get_session_type(),
|
||||
select_playlist=new_name,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
),
|
||||
from_window=self,
|
||||
is_back=True,
|
||||
)
|
||||
|
||||
def _save_press_with_sound(self) -> None:
|
||||
|
||||
@ -89,10 +89,8 @@ class PlaylistEditController:
|
||||
self._edit_ui_selection = 'add_button'
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition=transition
|
||||
).get_root_widget(),
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistEditWindow(editcontroller=self, transition=transition),
|
||||
from_window=False, # Disable this check.
|
||||
)
|
||||
|
||||
@ -149,10 +147,9 @@ class PlaylistEditController:
|
||||
from bauiv1lib.playlist.addgame import PlaylistAddGameWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_left')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistAddGameWindow(editcontroller=self).get_root_widget(),
|
||||
from_window=None,
|
||||
bui.app.ui_v1.clear_main_window()
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistAddGameWindow(editcontroller=self), from_window=None
|
||||
)
|
||||
|
||||
def edit_game_pressed(self) -> None:
|
||||
@ -168,18 +165,17 @@ class PlaylistEditController:
|
||||
settings=self._playlist[self._selected_index],
|
||||
)
|
||||
|
||||
def add_game_cancelled(self) -> None:
|
||||
"""(internal)"""
|
||||
from bauiv1lib.playlist.edit import PlaylistEditWindow
|
||||
# def add_game_cancelled(self) -> None:
|
||||
# """(internal)"""
|
||||
# from bauiv1lib.playlist.edit import PlaylistEditWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_right')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=None,
|
||||
)
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.clear_main_window(transition='out_right')
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# PlaylistEditWindow(editcontroller=self, transition='in_left'),
|
||||
# from_window=None,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _show_edit_ui(
|
||||
self, gametype: type[bs.GameActivity], settings: dict[str, Any] | None
|
||||
@ -204,22 +200,24 @@ class PlaylistEditController:
|
||||
# If we were editing, go back to our list.
|
||||
if self._editing_game:
|
||||
bui.getsound('powerdown01').play()
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_right')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.clear_main_window()
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget(),
|
||||
),
|
||||
from_window=None,
|
||||
is_back=True,
|
||||
)
|
||||
|
||||
# Otherwise we were adding; go back to the add type choice list.
|
||||
else:
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_right')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.clear_main_window()
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistAddGameWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget(),
|
||||
),
|
||||
from_window=None,
|
||||
is_back=True,
|
||||
)
|
||||
else:
|
||||
# Make sure type is in there.
|
||||
@ -237,10 +235,9 @@ class PlaylistEditController:
|
||||
self._selected_index = insert_index
|
||||
|
||||
bui.getsound('gunCocking').play()
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_right')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditWindow(
|
||||
editcontroller=self, transition='in_left'
|
||||
).get_root_widget(),
|
||||
bui.app.ui_v1.clear_main_window()
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistEditWindow(editcontroller=self, transition='in_left'),
|
||||
from_window=None,
|
||||
is_back=True,
|
||||
)
|
||||
|
||||
@ -7,7 +7,7 @@ from __future__ import annotations
|
||||
import copy
|
||||
import random
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from typing import TYPE_CHECKING, cast, override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
class PlaylistEditGameWindow(bui.Window):
|
||||
class PlaylistEditGameWindow(bui.MainWindow):
|
||||
"""Window for editing a game config."""
|
||||
|
||||
def __init__(
|
||||
@ -26,7 +26,8 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
config: dict[str, Any] | None,
|
||||
completion_call: Callable[[dict[str, Any] | None], Any],
|
||||
default_selection: str | None = None,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
edit_info: dict[str, Any] | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-branches
|
||||
@ -64,6 +65,7 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
bui.screenmessage(bui.Lstr(resource='noValidMapsErrorText'))
|
||||
raise RuntimeError('No valid maps found.')
|
||||
|
||||
self._config = config
|
||||
self._settings_defs = gametype.get_available_settings(sessiontype)
|
||||
self._completion_call = completion_call
|
||||
|
||||
@ -123,16 +125,17 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height + top_extra),
|
||||
transition=transition,
|
||||
scale=(
|
||||
2.19
|
||||
1.95
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -17) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
@ -161,13 +164,12 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
label=(
|
||||
bui.Lstr(resource=f'{self._r}.addGameText')
|
||||
if is_add
|
||||
else bui.Lstr(resource='doneText')
|
||||
else bui.Lstr(resource='applyText')
|
||||
),
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
pbtn = bui.get_special_widget('party_button')
|
||||
bui.widget(edit=add_button, right_widget=pbtn, up_widget=pbtn)
|
||||
pbtn = bui.get_special_widget('squad_button')
|
||||
bui.widget(edit=add_button, right_widget=pbtn, up_widget=pbtn)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -509,6 +511,29 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
edit=self._subcontainer, selected_child=map_button
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Pull things out of self here so we don't refer to self in the
|
||||
# lambda below which would keep us alive.
|
||||
gametype = self._gametype
|
||||
sessiontype = self._sessiontype
|
||||
config = self._config
|
||||
completion_call = self._completion_call
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
gametype=gametype,
|
||||
sessiontype=sessiontype,
|
||||
config=config,
|
||||
completion_call=completion_call,
|
||||
)
|
||||
)
|
||||
|
||||
def _get_localized_setting_name(self, name: str) -> bui.Lstr:
|
||||
return bui.Lstr(translate=('settingNames', name))
|
||||
|
||||
@ -523,15 +548,15 @@ class PlaylistEditGameWindow(bui.Window):
|
||||
# Replace ourself with the map-select UI.
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PlaylistMapSelectWindow(
|
||||
self._gametype,
|
||||
self._sessiontype,
|
||||
copy.deepcopy(self._getconfig()),
|
||||
self._edit_info,
|
||||
self._completion_call,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _choice_inc(
|
||||
|
||||
@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
||||
import bascenev1 as bs
|
||||
|
||||
|
||||
class PlaylistMapSelectWindow(bui.Window):
|
||||
class PlaylistMapSelectWindow(bui.MainWindow):
|
||||
"""Window to select a map."""
|
||||
|
||||
def __init__(
|
||||
@ -25,8 +25,11 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
config: dict[str, Any],
|
||||
edit_info: dict[str, Any],
|
||||
completion_call: Callable[[dict[str, Any] | None], Any],
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
from bascenev1 import get_filtered_map_name
|
||||
|
||||
self._gametype = gametype
|
||||
@ -56,16 +59,18 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height + top_extra),
|
||||
transition=transition,
|
||||
# transition=transition,
|
||||
scale=(
|
||||
2.17
|
||||
1.95
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -27) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._cancel_button = btn = bui.buttonwidget(
|
||||
@ -76,7 +81,7 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
text_scale=1.0,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='cancelText'),
|
||||
on_activate_call=self._cancel,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
@ -198,10 +203,10 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
bui.widget(edit=btn, left_widget=self._cancel_button)
|
||||
if y == 0:
|
||||
bui.widget(edit=btn, up_widget=self._cancel_button)
|
||||
if x == columns - 1 and bui.app.ui_v1.use_toolbars:
|
||||
if x == columns - 1:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
|
||||
bui.widget(edit=btn, show_buffer_top=60, show_buffer_bottom=60)
|
||||
@ -267,51 +272,53 @@ class PlaylistMapSelectWindow(bui.Window):
|
||||
self._refresh(select_get_more_maps_button=True)
|
||||
|
||||
def _select(self, map_name: str) -> None:
|
||||
from bauiv1lib.playlist.editgame import PlaylistEditGameWindow
|
||||
# from bauiv1lib.playlist.editgame import PlaylistEditGameWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._config['settings']['map'] = map_name
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditGameWindow(
|
||||
self._gametype,
|
||||
self._sessiontype,
|
||||
self._config,
|
||||
self._completion_call,
|
||||
default_selection='map',
|
||||
transition='in_left',
|
||||
edit_info=self._edit_info,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
self.main_window_back()
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# PlaylistEditGameWindow(
|
||||
# self._gametype,
|
||||
# self._sessiontype,
|
||||
# self._config,
|
||||
# self._completion_call,
|
||||
# default_selection='map',
|
||||
# transition='in_left',
|
||||
# edit_info=self._edit_info,
|
||||
# ),
|
||||
# from_window=self,
|
||||
# )
|
||||
|
||||
def _select_with_delay(self, map_name: str) -> None:
|
||||
bui.lock_all_input()
|
||||
bui.apptimer(0.1, bui.unlock_all_input)
|
||||
bui.apptimer(0.1, bui.WeakCall(self._select, map_name))
|
||||
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.playlist.editgame import PlaylistEditGameWindow
|
||||
# def _cancel(self) -> None:
|
||||
# from bauiv1lib.playlist.editgame import PlaylistEditGameWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PlaylistEditGameWindow(
|
||||
self._gametype,
|
||||
self._sessiontype,
|
||||
self._config,
|
||||
self._completion_call,
|
||||
default_selection='map',
|
||||
transition='in_left',
|
||||
edit_info=self._edit_info,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# PlaylistEditGameWindow(
|
||||
# self._gametype,
|
||||
# self._sessiontype,
|
||||
# self._config,
|
||||
# self._completion_call,
|
||||
# default_selection='map',
|
||||
# transition='in_left',
|
||||
# edit_info=self._edit_info,
|
||||
# ),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
@ -41,8 +41,9 @@ class PlayOptionsWindow(PopupWindow):
|
||||
|
||||
# We behave differently if we're being used for playlist selection
|
||||
# vs starting a game directly (should make this more elegant).
|
||||
assert bui.app.classic is not None
|
||||
self._selecting_mode = bui.app.ui_v1.selecting_private_party_playlist
|
||||
classic = bui.app.classic
|
||||
assert classic is not None
|
||||
self._selecting_mode = classic.selecting_private_party_playlist
|
||||
|
||||
self._do_randomize_val = bui.app.config.get(
|
||||
self._pvars.config_name + ' Playlist Randomize', 0
|
||||
@ -512,8 +513,8 @@ class PlayOptionsWindow(PopupWindow):
|
||||
# Note: this is a wonky situation where we aren't actually
|
||||
# the main window but we set it on behalf of the main window
|
||||
# that popped us up.
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GatherWindow(transition='in_right').get_root_widget(),
|
||||
bui.app.ui_v1.set_main_window(
|
||||
GatherWindow(transition='in_right'),
|
||||
from_window=False, # Disable this test.
|
||||
)
|
||||
self._transition_out(transition='out_left')
|
||||
|
||||
@ -10,7 +10,7 @@ from typing import TYPE_CHECKING, override
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any, Sequence, Callable
|
||||
from typing import Any, Sequence, Callable, Literal
|
||||
|
||||
|
||||
class PopupWindow:
|
||||
@ -27,7 +27,12 @@ class PopupWindow:
|
||||
bg_color: tuple[float, float, float] = (0.35, 0.55, 0.15),
|
||||
focus_position: tuple[float, float] = (0, 0),
|
||||
focus_size: tuple[float, float] | None = None,
|
||||
toolbar_visibility: str = 'menu_minimal_no_back',
|
||||
toolbar_visibility: Literal[
|
||||
'inherit',
|
||||
'menu_minimal_no_back',
|
||||
'menu_store_no_back',
|
||||
] = 'menu_minimal_no_back',
|
||||
edge_buffer_scale: float = 1.0,
|
||||
):
|
||||
# pylint: disable=too-many-locals
|
||||
if focus_size is None:
|
||||
@ -45,7 +50,7 @@ class PopupWindow:
|
||||
# we now need to ensure that we're all onscreen by scaling down if
|
||||
# need be and clamping it to the UI bounds.
|
||||
bounds = bui.uibounds()
|
||||
edge_buffer = 15
|
||||
edge_buffer = 15 * edge_buffer_scale
|
||||
bounds_width = bounds[1] - bounds[0] - edge_buffer * 2
|
||||
bounds_height = bounds[3] - bounds[2] - edge_buffer * 2
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import bauiv1 as bui
|
||||
import bascenev1 as bs
|
||||
@ -14,18 +14,17 @@ if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class ProfileBrowserWindow(bui.Window):
|
||||
class ProfileBrowserWindow(bui.MainWindow):
|
||||
"""Window for browsing player profiles."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
in_main_menu: bool = True,
|
||||
selected_profile: str | None = None,
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-locals
|
||||
self._in_main_menu = in_main_menu
|
||||
if self._in_main_menu:
|
||||
back_label = bui.Lstr(resource='backText')
|
||||
@ -46,15 +45,11 @@ class ProfileBrowserWindow(bui.Window):
|
||||
assert bui.app.classic is not None
|
||||
bui.app.classic.pause()
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
# Need to handle out-transitions ourself for modal mode.
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'playerProfilesWindow'
|
||||
|
||||
@ -67,30 +62,48 @@ class ProfileBrowserWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
2.2
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -14) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40 + x_inset, self._height - 59),
|
||||
size=(120, 60),
|
||||
scale=0.8,
|
||||
label=back_label,
|
||||
button_type='back' if self._in_main_menu else None,
|
||||
autoselect=True,
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
if bui.app.ui_v1.uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
)
|
||||
else:
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40 + x_inset, self._height - 59),
|
||||
size=(120, 60),
|
||||
scale=0.8,
|
||||
label=back_label,
|
||||
button_type='back' if self._in_main_menu else None,
|
||||
autoselect=True,
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
if self._in_main_menu:
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -104,14 +117,6 @@ class ProfileBrowserWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if self._in_main_menu:
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
scroll_height = self._height - 140.0
|
||||
self._scroll_width = self._width - (188 + x_inset * 2)
|
||||
v = self._height - 84.0
|
||||
@ -203,6 +208,20 @@ class ProfileBrowserWindow(bui.Window):
|
||||
self._refresh()
|
||||
self._restore_state()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _new_profile(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.profile.edit import EditProfileWindow
|
||||
@ -249,11 +268,11 @@ class ProfileBrowserWindow(bui.Window):
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.set_main_window(
|
||||
EditProfileWindow(
|
||||
existing_profile=None, in_main_menu=self._in_main_menu
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget if self._in_main_menu else False,
|
||||
),
|
||||
from_window=self if self._in_main_menu else False,
|
||||
)
|
||||
|
||||
def _delete_profile(self) -> None:
|
||||
@ -315,11 +334,11 @@ class ProfileBrowserWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
bui.app.ui_v1.set_main_window(
|
||||
EditProfileWindow(
|
||||
self._selected_profile, in_main_menu=self._in_main_menu
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget if self._in_main_menu else False,
|
||||
),
|
||||
from_window=self if self._in_main_menu else False,
|
||||
)
|
||||
|
||||
def _select(self, name: str, index: int) -> None:
|
||||
@ -328,7 +347,10 @@ class ProfileBrowserWindow(bui.Window):
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.account.settings import AccountSettingsWindow
|
||||
|
||||
if self._in_main_menu:
|
||||
self.main_window_back()
|
||||
return
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -340,16 +362,17 @@ class ProfileBrowserWindow(bui.Window):
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if self._in_main_menu:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AccountSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# if self._in_main_menu:
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# AccountSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
# If we're being called up standalone, handle pause/resume ourself.
|
||||
else:
|
||||
bui.app.classic.resume()
|
||||
# # If we're being called up standalone, handle pause/resume ourself.
|
||||
# else:
|
||||
bui.app.classic.resume()
|
||||
|
||||
def _refresh(self) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
|
||||
@ -5,17 +5,16 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from typing import cast
|
||||
from typing import cast, override
|
||||
|
||||
from bauiv1lib.colorpicker import ColorPicker
|
||||
import bauiv1 as bui
|
||||
import bascenev1 as bs
|
||||
|
||||
|
||||
class EditProfileWindow(bui.Window):
|
||||
class EditProfileWindow(bui.MainWindow):
|
||||
"""Window for editing a player profile."""
|
||||
|
||||
# FIXME: WILL NEED TO CHANGE THIS FOR UILOCATION.
|
||||
def reload_window(self) -> None:
|
||||
"""Transitions out and recreates ourself."""
|
||||
|
||||
@ -25,18 +24,18 @@ class EditProfileWindow(bui.Window):
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
EditProfileWindow(
|
||||
self.getname(), self._in_main_menu
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
EditProfileWindow(self.getname(), self._in_main_menu),
|
||||
from_window=self,
|
||||
is_back=True,
|
||||
)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
existing_profile: str | None,
|
||||
in_main_menu: bool,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# FIXME: Tidy this up a bit.
|
||||
# pylint: disable=too-many-branches
|
||||
@ -63,26 +62,32 @@ class EditProfileWindow(bui.Window):
|
||||
self._width = width = 880.0 if uiscale is bui.UIScale.SMALL else 680.0
|
||||
self._x_inset = x_inset = 100.0 if uiscale is bui.UIScale.SMALL else 0.0
|
||||
self._height = height = (
|
||||
350.0
|
||||
450.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 400.0 if uiscale is bui.UIScale.MEDIUM else 450.0
|
||||
)
|
||||
spacing = 40
|
||||
self._base_scale = (
|
||||
2.05
|
||||
1.6
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
)
|
||||
top_extra = 15 if uiscale is bui.UIScale.SMALL else 15
|
||||
top_extra = 70 if uiscale is bui.UIScale.SMALL else 15
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height + top_extra),
|
||||
transition=transition,
|
||||
scale=self._base_scale,
|
||||
stack_offset=(
|
||||
(0, 15) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, -40) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
cancel_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
@ -512,6 +517,19 @@ class EditProfileWindow(bui.Window):
|
||||
)
|
||||
self._update_character()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
existing_profile=self._existing_profile,
|
||||
in_main_menu=self._in_main_menu,
|
||||
)
|
||||
)
|
||||
|
||||
def assign_random_name(self) -> None:
|
||||
"""Assigning a random name to the player."""
|
||||
names = bs.get_random_names()
|
||||
@ -672,22 +690,24 @@ class EditProfileWindow(bui.Window):
|
||||
)
|
||||
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
self.main_window_back()
|
||||
# from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ProfileBrowserWindow(
|
||||
'in_left',
|
||||
selected_profile=self._existing_profile,
|
||||
in_main_menu=self._in_main_menu,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# ProfileBrowserWindow(
|
||||
# 'in_left',
|
||||
# selected_profile=self._existing_profile,
|
||||
# in_main_menu=self._in_main_menu,
|
||||
# ),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _set_color(self, color: tuple[float, float, float]) -> None:
|
||||
self._color = color
|
||||
@ -783,7 +803,6 @@ class EditProfileWindow(bui.Window):
|
||||
|
||||
def save(self, transition_out: bool = True) -> bool:
|
||||
"""Save has been selected."""
|
||||
from bauiv1lib.profile.browser import ProfileBrowserWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -840,14 +859,17 @@ class EditProfileWindow(bui.Window):
|
||||
|
||||
if transition_out:
|
||||
plus.run_v1_account_transactions()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ProfileBrowserWindow(
|
||||
'in_left',
|
||||
selected_profile=new_name,
|
||||
in_main_menu=self._in_main_menu,
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
self.main_window_back()
|
||||
# bui.containerwidget(edit=self._root_widget,
|
||||
# transition='out_right')
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# ProfileBrowserWindow(
|
||||
# 'in_left',
|
||||
# selected_profile=new_name,
|
||||
# in_main_menu=self._in_main_menu,
|
||||
# ),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
return True
|
||||
|
||||
@ -32,12 +32,12 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
|
||||
self._r = 'editProfileWindow'
|
||||
|
||||
self._width = 680
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 750 if uiscale is bui.UIScale.SMALL else 680
|
||||
self._height = 350
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._base_scale = (
|
||||
2.05
|
||||
1.9
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.2
|
||||
)
|
||||
@ -49,17 +49,17 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
toolbar_visibility='menu_currency',
|
||||
toolbar_visibility='menu_store_no_back',
|
||||
transition=transition,
|
||||
scale=self._base_scale,
|
||||
stack_offset=(
|
||||
(0, 15) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, -30) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
)
|
||||
cancel_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(52, 30),
|
||||
position=(52, 60),
|
||||
size=(155, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
@ -68,7 +68,7 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
)
|
||||
self._upgrade_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width - 190, 30),
|
||||
position=(self._width - 190, 60),
|
||||
size=(155, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
@ -136,20 +136,20 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
)
|
||||
|
||||
self._tickets_text: bui.Widget | None
|
||||
if not bui.app.ui_v1.use_toolbars:
|
||||
self._tickets_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.9 - 5, self._height - 30),
|
||||
size=(0, 0),
|
||||
text=bui.charstr(bui.SpecialChar.TICKET) + '123',
|
||||
color=(0.2, 1, 0.2),
|
||||
maxwidth=100,
|
||||
scale=0.5,
|
||||
h_align='right',
|
||||
v_align='center',
|
||||
)
|
||||
else:
|
||||
self._tickets_text = None
|
||||
# if not bui.app.ui_v1.use_toolbars:
|
||||
# self._tickets_text = bui.textwidget(
|
||||
# parent=self._root_widget,
|
||||
# position=(self._width * 0.9 - 5, self._height - 30),
|
||||
# size=(0, 0),
|
||||
# text=bui.charstr(bui.SpecialChar.TICKET) + '123',
|
||||
# color=(0.2, 1, 0.2),
|
||||
# maxwidth=100,
|
||||
# scale=0.5,
|
||||
# h_align='right',
|
||||
# v_align='center',
|
||||
# )
|
||||
# else:
|
||||
self._tickets_text = None
|
||||
|
||||
bui.app.classic.master_server_v1_get(
|
||||
'bsGlobalProfileCheck',
|
||||
@ -210,7 +210,7 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
)
|
||||
|
||||
def _on_upgrade_press(self) -> None:
|
||||
from bauiv1lib import gettickets
|
||||
# from bauiv1lib import gettickets
|
||||
|
||||
if self._status is None:
|
||||
plus = bui.app.plus
|
||||
@ -220,7 +220,8 @@ class ProfileUpgradeWindow(bui.Window):
|
||||
tickets = plus.get_v1_account_ticket_count()
|
||||
if tickets < self._cost:
|
||||
bui.getsound('error').play()
|
||||
gettickets.show_get_tickets_prompt()
|
||||
print('FIXME - show not-enough-tickets msg.')
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
return
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='purchasingText'), color=(0, 1, 0)
|
||||
|
||||
@ -44,7 +44,7 @@ class PurchaseWindow(bui.Window):
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_currency',
|
||||
toolbar_visibility='menu_store',
|
||||
scale=(
|
||||
1.2
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
@ -162,7 +162,7 @@ class PurchaseWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
def _purchase(self) -> None:
|
||||
from bauiv1lib import gettickets
|
||||
# from bauiv1lib import gettickets
|
||||
|
||||
plus = bui.app.plus
|
||||
assert plus is not None
|
||||
@ -176,7 +176,8 @@ class PurchaseWindow(bui.Window):
|
||||
except Exception:
|
||||
ticket_count = None
|
||||
if ticket_count is not None and ticket_count < self._price:
|
||||
gettickets.show_get_tickets_prompt()
|
||||
# gettickets.show_get_tickets_prompt()
|
||||
print('FIXME - show not-enough-tickets msg')
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
|
||||
@ -4,22 +4,29 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
from typing import override, TYPE_CHECKING, assert_never
|
||||
|
||||
from bauiv1lib.popup import PopupWindow
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Literal
|
||||
|
||||
|
||||
class ResourceTypeInfoWindow(PopupWindow):
|
||||
"""Popup window providing info about resource types."""
|
||||
|
||||
def __init__(self, origin_widget: bui.Widget):
|
||||
def __init__(
|
||||
self,
|
||||
resource_type: Literal['tickets', 'tokens', 'trophies', 'xp'],
|
||||
origin_widget: bui.Widget,
|
||||
):
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
scale = (
|
||||
2.3
|
||||
2.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.65 if uiscale is bui.UIScale.MEDIUM else 1.23
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
)
|
||||
self._transitioning_out = False
|
||||
self._width = 570
|
||||
@ -31,12 +38,13 @@ class ResourceTypeInfoWindow(PopupWindow):
|
||||
scale=scale,
|
||||
bg_color=bg_color,
|
||||
position=origin_widget.get_screen_space_center(),
|
||||
edge_buffer_scale=4.0,
|
||||
)
|
||||
self._cancel_button = bui.buttonwidget(
|
||||
parent=self.root_widget,
|
||||
position=(50, self._height - 30),
|
||||
position=(40, self._height - 40),
|
||||
size=(50, 50),
|
||||
scale=0.5,
|
||||
scale=0.7,
|
||||
label='',
|
||||
color=bg_color,
|
||||
on_activate_call=self._on_cancel_press,
|
||||
@ -45,6 +53,26 @@ class ResourceTypeInfoWindow(PopupWindow):
|
||||
iconscale=1.2,
|
||||
)
|
||||
|
||||
if resource_type == 'tickets':
|
||||
rdesc = 'Will describe tickets.'
|
||||
elif resource_type == 'tokens':
|
||||
rdesc = 'Will describe tokens.'
|
||||
elif resource_type == 'trophies':
|
||||
rdesc = 'Will show trophies & league rankings.'
|
||||
elif resource_type == 'xp':
|
||||
rdesc = 'Will describe xp/levels.'
|
||||
else:
|
||||
assert_never(resource_type)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self.root_widget,
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
size=(0, 0),
|
||||
position=(self._width * 0.5, self._height * 0.5),
|
||||
text=(f'UNDER CONSTRUCTION.\n({rdesc})'),
|
||||
)
|
||||
|
||||
def _on_cancel_press(self) -> None:
|
||||
self._transition_out()
|
||||
|
||||
|
||||
@ -14,26 +14,25 @@ if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class SendInfoWindow(bui.Window):
|
||||
class SendInfoWindow(bui.MainWindow):
|
||||
"""Window for sending info to the developer."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
modal: bool = False,
|
||||
legacy_code_mode: bool = False,
|
||||
transition: str | None = 'in_scale',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
self._legacy_code_mode = legacy_code_mode
|
||||
|
||||
scale_origin: tuple[float, float] | None
|
||||
# scale_origin: tuple[float, float] | None
|
||||
|
||||
# Need to wrangle our own transition-out in modal mode.
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
transition = 'in_right'
|
||||
|
||||
width = 450 if legacy_code_mode else 600
|
||||
height = 200 if legacy_code_mode else 300
|
||||
@ -46,15 +45,19 @@ class SendInfoWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal_no_back',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal_no_back'
|
||||
if uiscale is bui.UIScale.SMALL or modal
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
@ -165,7 +168,12 @@ class SendInfoWindow(bui.Window):
|
||||
|
||||
def _do_back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
if not self._modal:
|
||||
self.main_window_back()
|
||||
return
|
||||
|
||||
# from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -174,12 +182,13 @@ class SendInfoWindow(bui.Window):
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# if not self._modal:
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# AdvancedSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _activate_enter_button(self) -> None:
|
||||
self._enter_button.activate()
|
||||
@ -200,9 +209,8 @@ class SendInfoWindow(bui.Window):
|
||||
)
|
||||
if not self._modal:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
AdvancedSettingsWindow(transition='in_left'), from_window=self
|
||||
)
|
||||
|
||||
description: Any = bui.textwidget(query=self._text_field)
|
||||
|
||||
@ -6,7 +6,7 @@ from __future__ import annotations
|
||||
|
||||
import os
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from bauiv1lib.popup import PopupMenu
|
||||
import bauiv1 as bui
|
||||
@ -15,39 +15,28 @@ if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class AdvancedSettingsWindow(bui.Window):
|
||||
class AdvancedSettingsWindow(bui.MainWindow):
|
||||
"""Window for editing advanced app settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
import threading
|
||||
|
||||
if bui.app.classic is None:
|
||||
raise RuntimeError('This requires classic support.')
|
||||
|
||||
# Preload some modules we use in a background thread so we won't
|
||||
# have a visual hitch when the user taps them.
|
||||
threading.Thread(target=self._preload_modules).start()
|
||||
bui.app.threadpool_submit_no_wait(self._preload_modules)
|
||||
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 970.0 if uiscale is bui.UIScale.SMALL else 670.0
|
||||
self._width = 1030.0 if uiscale is bui.UIScale.SMALL else 670.0
|
||||
x_inset = 150 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
390.0
|
||||
@ -63,18 +52,22 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.06
|
||||
2.04
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -25) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, 10) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._prev_lang = ''
|
||||
@ -112,9 +105,9 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
|
||||
self._r = 'settingsWindowAdvanced'
|
||||
|
||||
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._do_back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._back_button = None
|
||||
else:
|
||||
@ -126,7 +119,7 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._do_back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
@ -134,12 +127,16 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, self._height - 52),
|
||||
size=(self._width, 25),
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (57 if uiscale is bui.UIScale.SMALL else 40),
|
||||
),
|
||||
size=(0, 0),
|
||||
scale=0.5 if uiscale is bui.UIScale.SMALL else 1.0,
|
||||
text=bui.Lstr(resource=f'{self._r}.titleText'),
|
||||
color=app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
if self._back_button is not None:
|
||||
@ -180,10 +177,23 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
callback=bui.WeakCall(self._completed_langs_cb),
|
||||
)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
"""Preload stuff in bg thread to avoid hitches in logic thread"""
|
||||
from babase import modutils as _unused2
|
||||
from bauiv1lib import config as _unused1
|
||||
from bauiv1lib.settings import vrtesting as _unused3
|
||||
@ -191,7 +201,7 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
from bauiv1lib import appinvite as _unused5
|
||||
from bauiv1lib import account as _unused6
|
||||
from bauiv1lib import sendinfo as _unused7
|
||||
from bauiv1lib import debug as _unused8
|
||||
from bauiv1lib import benchmarks as _unused8
|
||||
from bauiv1lib.settings import plugins as _unused9
|
||||
from bauiv1lib.settings import devtools as _unused10
|
||||
|
||||
@ -684,14 +694,13 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
for child in self._subcontainer.get_children():
|
||||
bui.widget(edit=child, show_buffer_bottom=30, show_buffer_top=20)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
pbtn = bui.get_special_widget('party_button')
|
||||
bui.widget(edit=self._scrollwidget, right_widget=pbtn)
|
||||
if self._back_button is None:
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
pbtn = bui.get_special_widget('squad_button')
|
||||
bui.widget(edit=self._scrollwidget, right_widget=pbtn)
|
||||
if self._back_button is None:
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
left_widget=bui.get_special_widget('back_button'),
|
||||
)
|
||||
|
||||
self._restore_state()
|
||||
|
||||
@ -719,9 +728,8 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
VRTestingWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
VRTestingWindow(transition='in_right'), from_window=self
|
||||
)
|
||||
|
||||
def _on_net_test_press(self) -> None:
|
||||
@ -736,9 +744,8 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
NetTestingWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
NetTestingWindow(transition='in_right'), from_window=self
|
||||
)
|
||||
|
||||
def _on_friend_promo_code_press(self) -> None:
|
||||
@ -763,9 +770,8 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PluginWindow(origin_widget=self._plugins_button).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PluginWindow(origin_widget=self._plugins_button), from_window=self
|
||||
)
|
||||
|
||||
def _on_dev_tools_button_press(self) -> None:
|
||||
@ -779,11 +785,9 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
DevToolsWindow(
|
||||
origin_widget=self._dev_tools_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
DevToolsWindow(origin_widget=self._dev_tools_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _on_send_info_press(self) -> None:
|
||||
@ -799,15 +803,13 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
SendInfoWindow(
|
||||
origin_widget=self._send_info_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
SendInfoWindow(origin_widget=self._send_info_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _on_benchmark_press(self) -> None:
|
||||
from bauiv1lib.debug import DebugWindow
|
||||
from bauiv1lib.benchmarks import BenchmarksAndStressTestsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -816,9 +818,9 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
DebugWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
BenchmarksAndStressTestsWindow(transition='in_right'),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
@ -974,19 +976,20 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._complete_langs_error = True
|
||||
bui.apptimer(0.001, bui.WeakCall(self._update_lang_status))
|
||||
|
||||
def _do_back(self) -> None:
|
||||
from bauiv1lib.settings.allsettings import AllSettingsWindow
|
||||
# def _do_back(self) -> None:
|
||||
# from bauiv1lib.settings.allsettings import AllSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AllSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# self._save_state()
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition=self._transition_out
|
||||
# )
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# AllSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
@ -4,8 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from threading import Thread
|
||||
from typing import TYPE_CHECKING, override
|
||||
import logging
|
||||
|
||||
import bauiv1 as bui
|
||||
@ -14,12 +13,12 @@ if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class AllSettingsWindow(bui.Window):
|
||||
class AllSettingsWindow(bui.MainWindow):
|
||||
"""Window for selecting a settings category."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
@ -27,17 +26,9 @@ class AllSettingsWindow(bui.Window):
|
||||
|
||||
# Preload some modules we use in a background thread so we won't
|
||||
# have a visual hitch when the user taps them.
|
||||
Thread(target=self._preload_modules).start()
|
||||
bui.app.threadpool_submit_no_wait(self._preload_modules)
|
||||
|
||||
bui.set_analytics_screen('Settings Window')
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 1000 if uiscale is bui.UIScale.SMALL else 580
|
||||
@ -50,24 +41,28 @@ class AllSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=(
|
||||
1.75
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.35 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.5
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.25 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -8) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = None
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._do_back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
@ -79,7 +74,7 @@ class AllSettingsWindow(bui.Window):
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._do_back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
@ -139,7 +134,7 @@ class AllSettingsWindow(bui.Window):
|
||||
label='',
|
||||
on_activate_call=self._do_controllers,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars and self._back_button is None:
|
||||
if self._back_button is None:
|
||||
bbtn = bui.get_special_widget('back_button')
|
||||
bui.widget(edit=ctb, left_widget=bbtn)
|
||||
_b_title(
|
||||
@ -163,9 +158,8 @@ class AllSettingsWindow(bui.Window):
|
||||
label='',
|
||||
on_activate_call=self._do_graphics,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
pbtn = bui.get_special_widget('party_button')
|
||||
bui.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn)
|
||||
pbtn = bui.get_special_widget('squad_button')
|
||||
bui.widget(edit=gfxb, up_widget=pbtn, right_widget=pbtn)
|
||||
_b_title(x_offs3, v, gfxb, bui.Lstr(resource=f'{self._r}.graphicsText'))
|
||||
imgw = imgh = 110
|
||||
bui.imagewidget(
|
||||
@ -219,7 +213,20 @@ class AllSettingsWindow(bui.Window):
|
||||
)
|
||||
self._restore_state()
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
@ -229,24 +236,6 @@ class AllSettingsWindow(bui.Window):
|
||||
import bauiv1lib.settings.audio as _unused4
|
||||
import bauiv1lib.settings.advanced as _unused5
|
||||
|
||||
def _do_back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.mainmenu import MainMenuWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
MainMenuWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _do_controllers(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
@ -258,11 +247,9 @@ class AllSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(
|
||||
origin_widget=self._controllers_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
ControlsSettingsWindow(origin_widget=self._controllers_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _do_graphics(self) -> None:
|
||||
@ -276,11 +263,9 @@ class AllSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GraphicsSettingsWindow(
|
||||
origin_widget=self._graphics_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
GraphicsSettingsWindow(origin_widget=self._graphics_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _do_audio(self) -> None:
|
||||
@ -294,11 +279,9 @@ class AllSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AudioSettingsWindow(
|
||||
origin_widget=self._audio_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
AudioSettingsWindow(origin_widget=self._audio_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _do_advanced(self) -> None:
|
||||
@ -312,11 +295,9 @@ class AllSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(
|
||||
origin_widget=self._advanced_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
AdvancedSettingsWindow(origin_widget=self._advanced_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
import logging
|
||||
|
||||
import bauiv1 as bui
|
||||
@ -13,12 +13,12 @@ if TYPE_CHECKING:
|
||||
pass
|
||||
|
||||
|
||||
class AudioSettingsWindow(bui.Window):
|
||||
class AudioSettingsWindow(bui.MainWindow):
|
||||
"""Window for editing audio settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
@ -30,16 +30,6 @@ class AudioSettingsWindow(bui.Window):
|
||||
assert bui.app.classic is not None
|
||||
music = bui.app.classic.music
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'audioSettingsWindow'
|
||||
|
||||
spacing = 50.0
|
||||
@ -70,13 +60,18 @@ class AudioSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
scale=base_scale,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
stack_offset=(
|
||||
(0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button = back_button = btn = bui.buttonwidget(
|
||||
@ -87,7 +82,7 @@ class AudioSettingsWindow(bui.Window):
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._back,
|
||||
on_activate_call=self.main_window_back,
|
||||
autoselect=True,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
@ -122,11 +117,10 @@ class AudioSettingsWindow(bui.Window):
|
||||
increment=0.05,
|
||||
as_percent=True,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=svne.plusbutton,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=svne.plusbutton,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
v -= spacing
|
||||
self._music_volume_numedit = ConfigNumberEdit(
|
||||
parent=self._root_widget,
|
||||
@ -226,6 +220,20 @@ class AudioSettingsWindow(bui.Window):
|
||||
|
||||
self._restore_state()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _set_vr_head_relative_audio(self, val: str) -> None:
|
||||
cfg = bui.app.config
|
||||
cfg['VR Head Relative Audio'] = val
|
||||
@ -255,31 +263,9 @@ class AudioSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
stb.SoundtrackBrowserWindow(
|
||||
origin_widget=self._soundtrack_button
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings import allsettings
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
allsettings.AllSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
stb.SoundtrackBrowserWindow(origin_widget=self._soundtrack_button),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
|
||||
@ -4,17 +4,19 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
from bauiv1lib.popup import PopupMenu
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class ControlsSettingsWindow(bui.Window):
|
||||
class ControlsSettingsWindow(bui.MainWindow):
|
||||
"""Top level control settings window."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# FIXME: should tidy up here.
|
||||
@ -25,30 +27,22 @@ class ControlsSettingsWindow(bui.Window):
|
||||
|
||||
self._have_selected_child = False
|
||||
|
||||
scale_origin: tuple[float, float] | None
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'configControllersWindow'
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
|
||||
spacing = 50.0
|
||||
button_width = 350.0
|
||||
width = 460.0
|
||||
height = 130.0
|
||||
width = 800.0 if uiscale is bui.UIScale.SMALL else 460.0
|
||||
height = 300 if uiscale is bui.UIScale.SMALL else 130.0
|
||||
|
||||
yoffs = -60 if uiscale is bui.UIScale.SMALL else 0
|
||||
space_height = spacing * 0.3
|
||||
|
||||
# FIXME: should create vis settings under platform or app-adapter
|
||||
# to determine whether to show this stuff; not hard code it.
|
||||
# FIXME: should create vis settings under platform or
|
||||
# app-adapter to determine whether to show this stuff; not hard
|
||||
# code it.
|
||||
|
||||
show_gamepads = False
|
||||
platform = app.classic.platform
|
||||
@ -111,13 +105,10 @@ class ControlsSettingsWindow(bui.Window):
|
||||
height += spacing
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
smallscale = 1.7 if show_keyboard else 2.2
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
stack_offset=(
|
||||
(0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
@ -126,20 +117,41 @@ class ControlsSettingsWindow(bui.Window):
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button: bui.Widget | None
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._back_button = None
|
||||
else:
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(35, height - 60),
|
||||
size=(140, 65),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
)
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(35, height - 60),
|
||||
size=(140, 65),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
# We need these vars to exist even if the buttons don't.
|
||||
self._gamepads_button: bui.Widget | None = None
|
||||
@ -150,21 +162,15 @@ class ControlsSettingsWindow(bui.Window):
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, height - 49),
|
||||
position=(0, height - 49 + yoffs),
|
||||
size=(width, 25),
|
||||
text=bui.Lstr(resource=f'{self._r}.titleText'),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
)
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
v = height - 75
|
||||
v = height - 75 + yoffs
|
||||
v -= spacing
|
||||
|
||||
if show_touch:
|
||||
@ -176,18 +182,18 @@ class ControlsSettingsWindow(bui.Window):
|
||||
label=bui.Lstr(resource=f'{self._r}.configureTouchText'),
|
||||
on_activate_call=self._do_touchscreen,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
if not self._have_selected_child:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._touch_button
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._touch_button
|
||||
)
|
||||
if self._back_button is not None:
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._touch_button
|
||||
)
|
||||
self._have_selected_child = True
|
||||
v -= spacing
|
||||
|
||||
@ -200,18 +206,19 @@ class ControlsSettingsWindow(bui.Window):
|
||||
label=bui.Lstr(resource=f'{self._r}.configureControllersText'),
|
||||
on_activate_call=self._do_gamepads,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
if not self._have_selected_child:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._gamepads_button
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._gamepads_button
|
||||
)
|
||||
if self._back_button is not None:
|
||||
bui.widget(
|
||||
edit=self._back_button,
|
||||
down_widget=self._gamepads_button,
|
||||
)
|
||||
self._have_selected_child = True
|
||||
v -= spacing
|
||||
else:
|
||||
@ -232,18 +239,19 @@ class ControlsSettingsWindow(bui.Window):
|
||||
bui.widget(
|
||||
edit=self._keyboard_button, left_widget=self._keyboard_button
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
if not self._have_selected_child:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._keyboard_button
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._keyboard_button
|
||||
)
|
||||
if self._back_button is not None:
|
||||
bui.widget(
|
||||
edit=self._back_button,
|
||||
down_widget=self._keyboard_button,
|
||||
)
|
||||
self._have_selected_child = True
|
||||
v -= spacing
|
||||
if show_keyboard_p2:
|
||||
@ -274,18 +282,19 @@ class ControlsSettingsWindow(bui.Window):
|
||||
bui.widget(
|
||||
edit=self._idevices_button, left_widget=self._idevices_button
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=btn,
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
if not self._have_selected_child:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, selected_child=self._idevices_button
|
||||
)
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._idevices_button
|
||||
)
|
||||
if self._back_button is not None:
|
||||
bui.widget(
|
||||
edit=self._back_button,
|
||||
down_widget=self._idevices_button,
|
||||
)
|
||||
self._have_selected_child = True
|
||||
v -= spacing
|
||||
|
||||
@ -371,6 +380,20 @@ class ControlsSettingsWindow(bui.Window):
|
||||
|
||||
self._restore_state()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _set_mac_controller_subsystem(self, val: str) -> None:
|
||||
cfg = bui.app.config
|
||||
cfg['Mac Controller Subsystem'] = val
|
||||
@ -387,11 +410,9 @@ class ControlsSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ConfigKeyboardWindow(
|
||||
bs.getinputdevice('Keyboard', '#1')
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
ConfigKeyboardWindow(bs.getinputdevice('Keyboard', '#1')),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _config_keyboard2(self) -> None:
|
||||
@ -405,11 +426,9 @@ class ControlsSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ConfigKeyboardWindow(
|
||||
bs.getinputdevice('Keyboard', '#2')
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
ConfigKeyboardWindow(bs.getinputdevice('Keyboard', '#2')),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _do_mobile_devices(self) -> None:
|
||||
@ -423,9 +442,8 @@ class ControlsSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
RemoteAppSettingsWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
RemoteAppSettingsWindow(), from_window=self
|
||||
)
|
||||
|
||||
def _do_gamepads(self) -> None:
|
||||
@ -439,10 +457,7 @@ class ControlsSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
GamepadSelectWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.app.ui_v1.set_main_window(GamepadSelectWindow(), from_window=self)
|
||||
|
||||
def _do_touchscreen(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
@ -455,9 +470,8 @@ class ControlsSettingsWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
TouchscreenSettingsWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
TouchscreenSettingsWindow(), from_window=self
|
||||
)
|
||||
|
||||
def _save_state(self) -> None:
|
||||
@ -500,20 +514,21 @@ class ControlsSettingsWindow(bui.Window):
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.allsettings import AllSettingsWindow
|
||||
# def _back(self) -> None:
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.settings.allsettings import AllSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AllSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# self._save_state()
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition=self._transition_out
|
||||
# )
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# AllSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
import babase
|
||||
import bauiv1 as bui
|
||||
from bauiv1lib.popup import PopupMenu
|
||||
@ -11,33 +13,23 @@ from bauiv1lib.confirm import ConfirmWindow
|
||||
from bauiv1lib.config import ConfigCheckBox
|
||||
|
||||
|
||||
class DevToolsWindow(bui.Window):
|
||||
class DevToolsWindow(bui.MainWindow):
|
||||
"""Window for accessing modding tools."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
uiscale = app.ui_v1.uiscale
|
||||
self._width = 970.0 if uiscale is bui.UIScale.SMALL else 670.0
|
||||
self._width = 1000.0 if uiscale is bui.UIScale.SMALL else 670.0
|
||||
x_inset = 150 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
390.0
|
||||
370.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 450.0 if uiscale is bui.UIScale.MEDIUM else 520.0
|
||||
)
|
||||
@ -53,25 +45,29 @@ class DevToolsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.06
|
||||
2.13
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -25) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, 0) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._r = 'settingsDevTools'
|
||||
|
||||
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._do_back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._back_button = None
|
||||
else:
|
||||
@ -83,7 +79,7 @@ class DevToolsWindow(bui.Window):
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._do_back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
@ -91,8 +87,12 @@ class DevToolsWindow(bui.Window):
|
||||
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 48),
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (64 if uiscale is bui.UIScale.SMALL else 48),
|
||||
),
|
||||
size=(0, 25),
|
||||
scale=(0.6 if uiscale is bui.UIScale.SMALL else 1.0),
|
||||
maxwidth=self._width - 200,
|
||||
text=bui.Lstr(resource='settingsWindowAdvanced.devToolsText'),
|
||||
color=app.ui_v1.title_color,
|
||||
@ -201,6 +201,16 @@ class DevToolsWindow(bui.Window):
|
||||
on_value_change_call=self._set_uiscale,
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def _set_uiscale(self, val: str) -> None:
|
||||
cfg = bui.app.config
|
||||
cfg['UI Scale'] = val
|
||||
@ -210,19 +220,3 @@ class DevToolsWindow(bui.Window):
|
||||
bui.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
|
||||
color=(1.0, 0.5, 0.0),
|
||||
)
|
||||
|
||||
def _do_back(self) -> None:
|
||||
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
||||
from bauiv1lib.popup import PopupWindow
|
||||
|
||||
|
||||
class GamepadSettingsWindow(bui.Window):
|
||||
class GamepadSettingsWindow(bui.MainWindow):
|
||||
"""Window for configuring a gamepad."""
|
||||
|
||||
# pylint: disable=too-many-public-methods
|
||||
@ -28,6 +28,7 @@ class GamepadSettingsWindow(bui.Window):
|
||||
is_main_menu: bool = True,
|
||||
transition: str = 'in_right',
|
||||
transition_out: str = 'out_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
settings: dict | None = None,
|
||||
):
|
||||
self._input = gamepad
|
||||
@ -63,7 +64,9 @@ class GamepadSettingsWindow(bui.Window):
|
||||
(-20, -16) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
transition=transition,
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._settings: dict[str, int] = {}
|
||||
@ -792,7 +795,7 @@ class GamepadSettingsWindow(bui.Window):
|
||||
return btn
|
||||
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
# from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
@ -802,11 +805,13 @@ class GamepadSettingsWindow(bui.Window):
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
if self._is_main_menu:
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
self.main_window_back()
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# ControlsSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _reset(self) -> None:
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
@ -937,9 +942,10 @@ class GamepadSettingsWindow(bui.Window):
|
||||
from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
ControlsSettingsWindow(transition='in_left'),
|
||||
from_window=self,
|
||||
is_back=True,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import bascenev1 as bs
|
||||
import bauiv1 as bui
|
||||
@ -16,15 +16,20 @@ if TYPE_CHECKING:
|
||||
|
||||
def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
"""Respond to a gamepad button press during config selection."""
|
||||
from bauiv1lib.settings import gamepad
|
||||
from bauiv1lib.settings.gamepad import GamepadSettingsWindow
|
||||
|
||||
# Ignore all but button-presses.
|
||||
if event['type'] not in ['BUTTONDOWN', 'HATMOTION']:
|
||||
return
|
||||
bs.release_gamepad_input()
|
||||
|
||||
if bool(True):
|
||||
bui.screenmessage('UNDER CONSTRUCTION')
|
||||
return
|
||||
|
||||
assert bui.app.classic is not None
|
||||
try:
|
||||
bui.app.ui_v1.clear_main_menu_window(transition='out_left')
|
||||
bui.app.ui_v1.clear_main_window()
|
||||
except Exception:
|
||||
logging.exception('Error transitioning out main_menu_window.')
|
||||
bui.getsound('activateBeep').play()
|
||||
@ -32,25 +37,34 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
device = event['input_device']
|
||||
assert isinstance(device, bs.InputDevice)
|
||||
if device.allows_configuring:
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
gamepad.GamepadSettingsWindow(device).get_root_widget(),
|
||||
from_window=None,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
GamepadSettingsWindow(device), from_window=None
|
||||
)
|
||||
else:
|
||||
width = 700
|
||||
height = 200
|
||||
button_width = 80
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
dlg = bui.containerwidget(
|
||||
scale=(
|
||||
1.7
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
size=(width, height),
|
||||
transition='in_right',
|
||||
)
|
||||
bui.app.ui_v1.set_main_menu_window(dlg, from_window=None)
|
||||
|
||||
class _Window(bui.MainWindow):
|
||||
def __init__(self) -> None:
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
scale=(
|
||||
1.7
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
size=(width, height),
|
||||
),
|
||||
transition='in_right',
|
||||
origin_widget=None,
|
||||
)
|
||||
|
||||
win = _Window()
|
||||
dlg = win.get_root_widget()
|
||||
|
||||
bui.app.ui_v1.set_main_window(win, from_window=None)
|
||||
|
||||
if device.allows_configuring_in_system_settings:
|
||||
msg = bui.Lstr(
|
||||
@ -86,11 +100,10 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
|
||||
bui.containerwidget(edit=dlg, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=dlg,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
controls.ControlsSettingsWindow(transition='in_left'),
|
||||
from_window=win,
|
||||
is_back=True,
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
@ -102,10 +115,14 @@ def gamepad_configure_callback(event: dict[str, Any]) -> None:
|
||||
)
|
||||
|
||||
|
||||
class GamepadSelectWindow(bui.Window):
|
||||
class GamepadSelectWindow(bui.MainWindow):
|
||||
"""Window for selecting a gamepad to configure."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
) -> None:
|
||||
from typing import cast
|
||||
|
||||
width = 480
|
||||
@ -123,8 +140,9 @@ class GamepadSelectWindow(bui.Window):
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
size=(width, height),
|
||||
transition='in_right',
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
@ -134,8 +152,9 @@ class GamepadSelectWindow(bui.Window):
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
scale=0.8,
|
||||
on_activate_call=self._back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
|
||||
# Let's not have anything selected by default; its misleading looking
|
||||
# for the controller getting configured.
|
||||
bui.containerwidget(
|
||||
@ -190,19 +209,16 @@ class GamepadSelectWindow(bui.Window):
|
||||
|
||||
bs.capture_gamepad_input(gamepad_configure_callback)
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.settings import controls
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bs.release_gamepad_input()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
bs.release_gamepad_input()
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, cast
|
||||
from typing import TYPE_CHECKING, cast, override
|
||||
|
||||
from bauiv1lib.popup import PopupMenu
|
||||
from bauiv1lib.config import ConfigCheckBox
|
||||
@ -14,28 +14,18 @@ if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
|
||||
class GraphicsSettingsWindow(bui.Window):
|
||||
class GraphicsSettingsWindow(bui.MainWindow):
|
||||
"""Window for graphics settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-branches
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
# if they provided an origin-widget, scale up from that
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'graphicsSettingsWindow'
|
||||
app = bui.app
|
||||
assert app.classic is not None
|
||||
@ -73,9 +63,9 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
base_scale = (
|
||||
2.0
|
||||
1.5
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.5 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
)
|
||||
popup_menu_scale = base_scale * 1.2
|
||||
v = height - 50
|
||||
@ -83,13 +73,18 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition=transition,
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
scale=base_scale,
|
||||
stack_offset=(
|
||||
(0, -30) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, -10) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
back_button = bui.buttonwidget(
|
||||
@ -102,7 +97,7 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
autoselect=True,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
on_activate_call=self._back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=back_button)
|
||||
@ -215,11 +210,10 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
current_choice=bui.app.config.resolve('Texture Quality'),
|
||||
on_value_change_call=self._set_textures,
|
||||
)
|
||||
if bui.app.ui_v1.use_toolbars:
|
||||
bui.widget(
|
||||
edit=textures_popup.get_button(),
|
||||
right_widget=bui.get_special_widget('party_button'),
|
||||
)
|
||||
bui.widget(
|
||||
edit=textures_popup.get_button(),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
v -= 80
|
||||
|
||||
h_offs = 0
|
||||
@ -433,28 +427,20 @@ class GraphicsSettingsWindow(bui.Window):
|
||||
0.25, bui.WeakCall(self._update_controls), repeat=True
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.settings import allsettings
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
# Applying max-fps takes a few moments. Apply if it hasn't been
|
||||
# yet.
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._apply_max_fps()
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
allsettings.AllSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _set_quality(self, quality: str) -> None:
|
||||
cfg = bui.app.config
|
||||
cfg['Graphics Quality'] = quality
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from bauiv1lib.popup import PopupMenuWindow
|
||||
import bauiv1 as bui
|
||||
@ -12,13 +12,19 @@ import bascenev1 as bs
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
from bauiv1lib.popup import PopupWindow
|
||||
|
||||
|
||||
class ConfigKeyboardWindow(bui.Window):
|
||||
class ConfigKeyboardWindow(bui.MainWindow):
|
||||
"""Window for configuring keyboards."""
|
||||
|
||||
def __init__(self, c: bs.InputDevice, transition: str = 'in_right'):
|
||||
def __init__(
|
||||
self,
|
||||
c: bs.InputDevice,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
self._r = 'configKeyboardWindow'
|
||||
self._input = c
|
||||
self._name = self._input.name
|
||||
@ -39,13 +45,15 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
scale=(
|
||||
1.6
|
||||
1.4
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(0, 5) if uiscale is bui.UIScale.SMALL else (0, 0),
|
||||
transition=transition,
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._settings: dict[str, int] = {}
|
||||
@ -53,6 +61,23 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
|
||||
self._rebuild_ui()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
|
||||
# Pull things from self here; if we do it within the lambda
|
||||
# we'll keep self alive which is bad.
|
||||
inputdevice = self._input
|
||||
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
c=inputdevice,
|
||||
)
|
||||
)
|
||||
|
||||
def _get_config_mapping(self, default: bool = False) -> None:
|
||||
for button in [
|
||||
'buttonJump',
|
||||
@ -87,7 +112,7 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
size=(170, 60),
|
||||
label=bui.Lstr(resource='cancelText'),
|
||||
scale=0.9,
|
||||
on_activate_call=self._cancel,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
save_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
@ -287,20 +312,6 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
|
||||
bui.pushcall(doit)
|
||||
|
||||
def _cancel(self) -> None:
|
||||
from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
def _reset(self) -> None:
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
@ -366,14 +377,14 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
"""Called when the popup is closing."""
|
||||
|
||||
def _save(self) -> None:
|
||||
from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
# from bauiv1lib.settings.controls import ControlsSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
bui.getsound('gunCocking').play()
|
||||
|
||||
# There's a chance the device disappeared; handle that gracefully.
|
||||
@ -405,10 +416,13 @@ class ConfigKeyboardWindow(bui.Window):
|
||||
},
|
||||
)
|
||||
bui.app.config.apply_and_commit()
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
ControlsSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
self.main_window_back()
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# ControlsSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
|
||||
class AwaitKeyboardInputWindow(bui.Window):
|
||||
|
||||
@ -8,7 +8,7 @@ import time
|
||||
import copy
|
||||
import weakref
|
||||
from threading import Thread
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
from efro.error import CleanError
|
||||
from bauiv1lib.settings.testing import TestingWindow
|
||||
@ -22,40 +22,53 @@ if TYPE_CHECKING:
|
||||
MAX_TEST_SECONDS = 60 * 2
|
||||
|
||||
|
||||
class NetTestingWindow(bui.Window):
|
||||
class NetTestingWindow(bui.MainWindow):
|
||||
"""Window that runs a networking test suite to help diagnose issues."""
|
||||
|
||||
def __init__(self, transition: str = 'in_right'):
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 820
|
||||
self._height = 500
|
||||
self._height = 400 if uiscale is bui.UIScale.SMALL else 500
|
||||
self._printed_lines: list[str] = []
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
scale=(
|
||||
1.56
|
||||
1.75
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.2 if uiscale is bui.UIScale.MEDIUM else 0.8
|
||||
),
|
||||
stack_offset=(0.0, -7 if uiscale is bui.UIScale.SMALL else 0.0),
|
||||
transition=transition,
|
||||
)
|
||||
stack_offset=(0, -4 if uiscale is bui.UIScale.SMALL else 0.0),
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
self._done_button = bui.buttonwidget(
|
||||
self._done_button: bui.Widget | None = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40, self._height - 77),
|
||||
position=(46, self._height - 77),
|
||||
size=(120, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='doneText'),
|
||||
on_activate_call=self._done,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
|
||||
# Avoid squads button on small mode.
|
||||
xinset = -50 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
self._copy_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width - 200, self._height - 77),
|
||||
position=(self._width - 200 + xinset, self._height - 77),
|
||||
size=(100, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
@ -65,7 +78,7 @@ class NetTestingWindow(bui.Window):
|
||||
|
||||
self._settings_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width - 100, self._height - 77),
|
||||
position=(self._width - 100 + xinset, self._height - 77),
|
||||
size=(60, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
@ -73,7 +86,7 @@ class NetTestingWindow(bui.Window):
|
||||
on_activate_call=self._show_val_testing,
|
||||
)
|
||||
|
||||
twidth = self._width - 450
|
||||
twidth = self._width - 540
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 55),
|
||||
@ -94,9 +107,16 @@ class NetTestingWindow(bui.Window):
|
||||
)
|
||||
self._rows = bui.columnwidget(parent=self._scroll)
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._done_button
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._done_button.delete()
|
||||
self._done_button = None
|
||||
else:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._done_button
|
||||
)
|
||||
|
||||
# Now kick off the tests.
|
||||
# Pass a weak-ref to this window so we don't keep it alive
|
||||
@ -107,6 +127,16 @@ class NetTestingWindow(bui.Window):
|
||||
target=bui.Call(_run_diagnostics, weakref.ref(self)),
|
||||
).start()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def print(self, text: str, color: tuple[float, float, float]) -> None:
|
||||
"""Print text to our console thingie."""
|
||||
for line in text.splitlines():
|
||||
@ -138,26 +168,24 @@ class NetTestingWindow(bui.Window):
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
NetValTestingWindow().get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.app.ui_v1.set_main_window(NetValTestingWindow(), from_window=self)
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
|
||||
def _done(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
# def _done(self) -> None:
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# AdvancedSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
# bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
|
||||
|
||||
def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None:
|
||||
@ -471,5 +499,4 @@ class NetValTestingWindow(TestingWindow):
|
||||
title=bui.Lstr(resource='settingsWindowAdvanced.netTestingText'),
|
||||
entries=entries,
|
||||
transition=transition,
|
||||
back_call=lambda: NetTestingWindow(transition='in_left'),
|
||||
)
|
||||
|
||||
@ -4,9 +4,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from enum import Enum
|
||||
import logging
|
||||
from typing import TYPE_CHECKING, assert_never
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, assert_never, override
|
||||
|
||||
import bauiv1 as bui
|
||||
from bauiv1lib import popup
|
||||
@ -28,35 +28,24 @@ class Category(Enum):
|
||||
return f'{self.value}Text'
|
||||
|
||||
|
||||
class PluginWindow(bui.Window):
|
||||
class PluginWindow(bui.MainWindow):
|
||||
"""Window for configuring plugins."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-statements
|
||||
app = bui.app
|
||||
|
||||
self._category = Category.ALL
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 870.0 if uiscale is bui.UIScale.SMALL else 670.0
|
||||
x_inset = 100 if uiscale is bui.UIScale.SMALL else 0
|
||||
self._height = (
|
||||
390.0
|
||||
370.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 450.0 if uiscale is bui.UIScale.MEDIUM else 520.0
|
||||
)
|
||||
@ -64,18 +53,22 @@ class PluginWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.06
|
||||
1.9
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -25) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._scroll_width = self._width - (100 + 2 * x_inset)
|
||||
@ -84,9 +77,9 @@ class PluginWindow(bui.Window):
|
||||
self._sub_height = 724.0
|
||||
|
||||
assert app.classic is not None
|
||||
if app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._do_back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
self._back_button = None
|
||||
else:
|
||||
@ -98,7 +91,7 @@ class PluginWindow(bui.Window):
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._do_back,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
@ -213,6 +206,20 @@ class PluginWindow(bui.Window):
|
||||
)
|
||||
self._restore_state()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _check_value_changed(self, plug: bui.PluginSpec, value: bool) -> None:
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='settingsWindowAdvanced.mustRestartText'),
|
||||
@ -235,9 +242,8 @@ class PluginWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PluginSettingsWindow(transition='in_right').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
PluginSettingsWindow(transition='in_right'), from_window=self
|
||||
)
|
||||
|
||||
def _show_category_options(self) -> None:
|
||||
@ -451,21 +457,3 @@ class PluginWindow(bui.Window):
|
||||
bui.containerwidget(edit=self._root_widget, selected_child=sel)
|
||||
except Exception:
|
||||
logging.exception('Error restoring state for %s.', self)
|
||||
|
||||
def _do_back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AdvancedSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -4,21 +4,24 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
import bauiv1 as bui
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
|
||||
class PluginSettingsWindow(bui.Window):
|
||||
class PluginSettingsWindow(bui.MainWindow):
|
||||
"""Plugin Settings Window"""
|
||||
|
||||
def __init__(self, transition: str = 'in_right'):
|
||||
scale_origin: tuple[float, float] | None
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
width = 470.0 if uiscale is bui.UIScale.SMALL else 470.0
|
||||
width = 670.0 if uiscale is bui.UIScale.SMALL else 470.0
|
||||
height = (
|
||||
365.0
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
@ -29,9 +32,11 @@ class PluginSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height + top_extra),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.06
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
@ -40,37 +45,50 @@ class PluginSettingsWindow(bui.Window):
|
||||
stack_offset=(
|
||||
(0, -25) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(53, height - 60),
|
||||
size=(60, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
on_activate_call=self._do_back,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
xoffs = 90
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
else:
|
||||
xoffs = 0
|
||||
self._back_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(53, height - 60),
|
||||
size=(60, 60),
|
||||
scale=0.8,
|
||||
autoselect=True,
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
button_type='backSmall',
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
|
||||
self._title_text = bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(0, height - 52),
|
||||
size=(width, 25),
|
||||
position=(
|
||||
width * 0.5,
|
||||
height - (45 if uiscale is bui.UIScale.SMALL else 35),
|
||||
),
|
||||
size=(0, 0),
|
||||
text=bui.Lstr(resource='pluginSettingsText'),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
v_align='top',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
self._y_position = 170 if uiscale is bui.UIScale.MEDIUM else 205
|
||||
self._enable_plugins_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(65, self._y_position),
|
||||
position=(xoffs + 65, self._y_position),
|
||||
size=(350, 60),
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='pluginsEnableAllText'),
|
||||
@ -83,7 +101,7 @@ class PluginSettingsWindow(bui.Window):
|
||||
self._y_position -= 70
|
||||
self._disable_plugins_button = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(65, self._y_position),
|
||||
position=(xoffs + 65, self._y_position),
|
||||
size=(350, 60),
|
||||
autoselect=True,
|
||||
label=bui.Lstr(resource='pluginsDisableAllText'),
|
||||
@ -96,7 +114,7 @@ class PluginSettingsWindow(bui.Window):
|
||||
self._y_position -= 70
|
||||
self._enable_new_plugins_check_box = bui.checkboxwidget(
|
||||
parent=self._root_widget,
|
||||
position=(65, self._y_position),
|
||||
position=(xoffs + 65, self._y_position),
|
||||
size=(350, 60),
|
||||
value=bui.app.config.get(
|
||||
bui.app.plugins.AUTO_ENABLE_NEW_PLUGINS_CONFIG_KEY,
|
||||
@ -108,9 +126,10 @@ class PluginSettingsWindow(bui.Window):
|
||||
on_value_change_call=self._update_value,
|
||||
)
|
||||
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._enable_plugins_button
|
||||
)
|
||||
if uiscale is not bui.UIScale.SMALL:
|
||||
bui.widget(
|
||||
edit=self._back_button, down_widget=self._enable_plugins_button
|
||||
)
|
||||
|
||||
bui.widget(
|
||||
edit=self._disable_plugins_button,
|
||||
@ -124,6 +143,16 @@ class PluginSettingsWindow(bui.Window):
|
||||
down_widget=self._enable_new_plugins_check_box,
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def _enable_all_plugins(self) -> None:
|
||||
cfg = bui.app.config
|
||||
plugs: dict[str, dict] = cfg.setdefault('Plugins', {})
|
||||
@ -152,20 +181,3 @@ class PluginSettingsWindow(bui.Window):
|
||||
cfg = bui.app.config
|
||||
cfg[bui.app.plugins.AUTO_ENABLE_NEW_PLUGINS_CONFIG_KEY] = val
|
||||
cfg.apply_and_commit()
|
||||
|
||||
def _do_back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.plugins import PluginWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
PluginWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -4,45 +4,70 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
|
||||
class RemoteAppSettingsWindow(bui.Window):
|
||||
class RemoteAppSettingsWindow(bui.MainWindow):
|
||||
"""Window showing info/settings related to the remote app."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
) -> None:
|
||||
self._r = 'connectMobileDevicesWindow'
|
||||
width = 700
|
||||
app = bui.app
|
||||
uiscale = app.ui_v1.uiscale
|
||||
width = 800 if uiscale is bui.UIScale.SMALL else 700
|
||||
height = 390
|
||||
spacing = 40
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(width, height),
|
||||
transition='in_right',
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
1.85
|
||||
1.76
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.3 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(-10, 0) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
bui.containerwidget(
|
||||
edit=self.get_root_widget(),
|
||||
on_cancel_call=self.main_window_back,
|
||||
)
|
||||
else:
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40, height - 67),
|
||||
size=(140, 65),
|
||||
scale=0.8,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
text_scale=1.1,
|
||||
autoselect=True,
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
)
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
position=(40, height - 67),
|
||||
size=(140, 65),
|
||||
scale=0.8,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
text_scale=1.1,
|
||||
autoselect=True,
|
||||
on_activate_call=self._back,
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
@ -56,13 +81,6 @@ class RemoteAppSettingsWindow(bui.Window):
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=btn,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
v = height - 70.0
|
||||
v -= spacing * 1.2
|
||||
bui.textwidget(
|
||||
@ -125,23 +143,17 @@ class RemoteAppSettingsWindow(bui.Window):
|
||||
on_value_change_call=self._on_check_changed,
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def _on_check_changed(self, value: bool) -> None:
|
||||
cfg = bui.app.config
|
||||
cfg['Enable Remote App'] = not value
|
||||
cfg.apply_and_commit()
|
||||
|
||||
def _back(self) -> None:
|
||||
from bauiv1lib.settings import controls
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
|
||||
@ -13,50 +13,73 @@ if TYPE_CHECKING:
|
||||
from typing import Any, Callable
|
||||
|
||||
|
||||
class TestingWindow(bui.Window):
|
||||
class TestingWindow(bui.MainWindow):
|
||||
"""Window for conveniently testing various settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
title: bui.Lstr,
|
||||
entries: list[dict[str, Any]],
|
||||
transition: str = 'in_right',
|
||||
back_call: Callable[[], bui.Window] | None = None,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
self._width = 600
|
||||
self._width = 700 if uiscale is bui.UIScale.SMALL else 600
|
||||
self._height = 324 if uiscale is bui.UIScale.SMALL else 400
|
||||
self._entries = copy.deepcopy(entries)
|
||||
self._back_call = back_call
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition=transition,
|
||||
scale=(
|
||||
2.5
|
||||
2.27
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.2 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -28) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
(0, -20) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = bui.get_special_widget('back_button')
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
)
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(65, self._height - 59),
|
||||
size=(130, 60),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self._do_back,
|
||||
)
|
||||
else:
|
||||
self._back_button = btn = bui.buttonwidget(
|
||||
parent=self._root_widget,
|
||||
autoselect=True,
|
||||
position=(65, self._height - 59),
|
||||
size=(130, 60),
|
||||
scale=0.8,
|
||||
text_scale=1.2,
|
||||
label=bui.Lstr(resource='backText'),
|
||||
button_type='back',
|
||||
on_activate_call=self.main_window_back,
|
||||
)
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 35),
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (42 if uiscale is bui.UIScale.SMALL else 35),
|
||||
),
|
||||
size=(0, 0),
|
||||
color=bui.app.ui_v1.title_color,
|
||||
h_align='center',
|
||||
@ -65,16 +88,12 @@ class TestingWindow(bui.Window):
|
||||
text=title,
|
||||
)
|
||||
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button,
|
||||
button_type='backSmall',
|
||||
size=(60, 60),
|
||||
label=bui.charstr(bui.SpecialChar.BACK),
|
||||
)
|
||||
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height - 75),
|
||||
position=(
|
||||
self._width * 0.5,
|
||||
self._height - (80 if uiscale is bui.UIScale.SMALL else 80),
|
||||
),
|
||||
size=(0, 0),
|
||||
color=bui.app.ui_v1.infotextcolor,
|
||||
h_align='center',
|
||||
@ -82,7 +101,6 @@ class TestingWindow(bui.Window):
|
||||
maxwidth=self._width * 0.75,
|
||||
text=bui.Lstr(resource='settingsWindowAdvanced.forTestingText'),
|
||||
)
|
||||
bui.containerwidget(edit=self._root_widget, cancel_button=btn)
|
||||
self._scroll_width = self._width - 130
|
||||
self._scroll_height = self._height - 140
|
||||
self._scrollwidget = bui.scrollwidget(
|
||||
@ -138,7 +156,6 @@ class TestingWindow(bui.Window):
|
||||
)
|
||||
if i == 0:
|
||||
bui.widget(edit=btn, up_widget=self._back_button)
|
||||
# pylint: disable=consider-using-f-string
|
||||
entry['widget'] = bui.textwidget(
|
||||
parent=self._subcontainer,
|
||||
position=(h + 100, v),
|
||||
@ -146,7 +163,7 @@ class TestingWindow(bui.Window):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
maxwidth=60,
|
||||
text='%.4g' % bui.app.classic.value_test(entry_name),
|
||||
text=f'{bui.app.classic.value_test(entry_name):.4g}',
|
||||
)
|
||||
btn = bui.buttonwidget(
|
||||
parent=self._subcontainer,
|
||||
@ -185,10 +202,9 @@ class TestingWindow(bui.Window):
|
||||
entry['name'],
|
||||
absolute=bui.app.classic.value_test_defaults[entry['name']],
|
||||
)
|
||||
# pylint: disable=consider-using-f-string
|
||||
bui.textwidget(
|
||||
edit=entry['widget'],
|
||||
text='%.4g' % bui.app.classic.value_test(entry['name']),
|
||||
text=f'{bui.app.classic.value_test(entry['name']):.4g}',
|
||||
)
|
||||
|
||||
def _on_minus_press(self, entry_name: str) -> None:
|
||||
@ -210,22 +226,3 @@ class TestingWindow(bui.Window):
|
||||
edit=entry['widget'],
|
||||
text='%.4g' % bui.app.classic.value_test(entry['name']),
|
||||
)
|
||||
|
||||
def _do_back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.advanced import AdvancedSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
backwin = (
|
||||
self._back_call()
|
||||
if self._back_call is not None
|
||||
else AdvancedSettingsWindow(transition='in_left')
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
backwin.get_root_widget(), from_window=self._root_widget
|
||||
)
|
||||
|
||||
@ -3,11 +3,13 @@
|
||||
"""UI settings functionality related to touchscreens."""
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import override
|
||||
|
||||
import bauiv1 as bui
|
||||
import bascenev1 as bs
|
||||
|
||||
|
||||
class TouchscreenSettingsWindow(bui.Window):
|
||||
class TouchscreenSettingsWindow(bui.MainWindow):
|
||||
"""Settings window for touchscreens."""
|
||||
|
||||
def __del__(self) -> None:
|
||||
@ -18,7 +20,11 @@ class TouchscreenSettingsWindow(bui.Window):
|
||||
# thing that exists.
|
||||
bs.set_touchscreen_editing(False)
|
||||
|
||||
def __init__(self) -> None:
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
) -> None:
|
||||
self._width = 650
|
||||
self._height = 380
|
||||
self._spacing = 40
|
||||
@ -31,13 +37,14 @@ class TouchscreenSettingsWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition='in_right',
|
||||
scale=(
|
||||
1.9
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.55 if uiscale is bui.UIScale.MEDIUM else 1.2
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
btn = bui.buttonwidget(
|
||||
@ -95,6 +102,16 @@ class TouchscreenSettingsWindow(bui.Window):
|
||||
)
|
||||
self._build_gui()
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
def _build_gui(self) -> None:
|
||||
from bauiv1lib.config import ConfigNumberEdit, ConfigCheckBox
|
||||
from bauiv1lib.radiogroup import make_radio_group
|
||||
@ -280,10 +297,9 @@ class TouchscreenSettingsWindow(bui.Window):
|
||||
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_right')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
controls.ControlsSettingsWindow(
|
||||
transition='in_left'
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
controls.ControlsSettingsWindow(transition='in_left'),
|
||||
from_window=self,
|
||||
is_back=True,
|
||||
)
|
||||
bs.set_touchscreen_editing(False)
|
||||
|
||||
@ -6,35 +6,29 @@ from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import logging
|
||||
from typing import TYPE_CHECKING
|
||||
from typing import TYPE_CHECKING, override
|
||||
|
||||
import bauiv1 as bui
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from typing import Any
|
||||
|
||||
REQUIRE_PRO = False
|
||||
|
||||
class SoundtrackBrowserWindow(bui.Window):
|
||||
# Temp.
|
||||
UNDER_CONSTRUCTION = True
|
||||
|
||||
|
||||
class SoundtrackBrowserWindow(bui.MainWindow):
|
||||
"""Window for browsing soundtracks."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str = 'in_right',
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
|
||||
# If they provided an origin-widget, scale up from that.
|
||||
scale_origin: tuple[float, float] | None
|
||||
if origin_widget is not None:
|
||||
self._transition_out = 'out_scale'
|
||||
scale_origin = origin_widget.get_screen_space_center()
|
||||
transition = 'in_scale'
|
||||
else:
|
||||
self._transition_out = 'out_right'
|
||||
scale_origin = None
|
||||
|
||||
self._r = 'editSoundtrackWindow'
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
@ -52,22 +46,26 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height),
|
||||
transition=transition,
|
||||
toolbar_visibility='menu_minimal',
|
||||
scale_origin_stack_offset=scale_origin,
|
||||
toolbar_visibility=(
|
||||
'menu_minimal'
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 'menu_full'
|
||||
),
|
||||
scale=(
|
||||
2.3
|
||||
2.1
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else 1.6 if uiscale is bui.UIScale.MEDIUM else 1.0
|
||||
),
|
||||
stack_offset=(
|
||||
(0, -18) if uiscale is bui.UIScale.SMALL else (0, 0)
|
||||
),
|
||||
)
|
||||
),
|
||||
transition=transition,
|
||||
origin_widget=origin_widget,
|
||||
)
|
||||
|
||||
assert bui.app.classic is not None
|
||||
if bui.app.ui_v1.use_toolbars and uiscale is bui.UIScale.SMALL:
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
self._back_button = None
|
||||
else:
|
||||
self._back_button = bui.buttonwidget(
|
||||
@ -239,11 +237,7 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
bui.widget(
|
||||
edit=self._scrollwidget,
|
||||
left_widget=self._new_button,
|
||||
right_widget=(
|
||||
bui.get_special_widget('party_button')
|
||||
if bui.app.ui_v1.use_toolbars
|
||||
else self._scrollwidget
|
||||
),
|
||||
right_widget=bui.get_special_widget('squad_button'),
|
||||
)
|
||||
self._col = bui.columnwidget(parent=scrollwidget, border=2, margin=0)
|
||||
|
||||
@ -255,23 +249,39 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
self._refresh()
|
||||
if self._back_button is not None:
|
||||
bui.buttonwidget(
|
||||
edit=self._back_button, on_activate_call=self._back
|
||||
edit=self._back_button, on_activate_call=self.main_window_back
|
||||
)
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
)
|
||||
else:
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, on_cancel_call=self._back
|
||||
edit=self._root_widget, on_cancel_call=self.main_window_back
|
||||
)
|
||||
|
||||
@override
|
||||
def get_main_window_state(self) -> bui.MainWindowState:
|
||||
# Support recreating our window for back/refresh purposes.
|
||||
cls = type(self)
|
||||
return bui.BasicMainWindowState(
|
||||
create_call=lambda transition, origin_widget: cls(
|
||||
transition=transition, origin_widget=origin_widget
|
||||
)
|
||||
)
|
||||
|
||||
@override
|
||||
def on_main_window_close(self) -> None:
|
||||
self._save_state()
|
||||
|
||||
def _update(self) -> None:
|
||||
have = (
|
||||
have_pro = (
|
||||
bui.app.classic is None
|
||||
or bui.app.classic.accounts.have_pro_options()
|
||||
)
|
||||
for lock in self._lock_images:
|
||||
bui.imagewidget(edit=lock, opacity=0.0 if have else 1.0)
|
||||
bui.imagewidget(
|
||||
edit=lock, opacity=0.0 if (have_pro or not REQUIRE_PRO) else 1.0
|
||||
)
|
||||
|
||||
def _do_delete_soundtrack(self) -> None:
|
||||
cfg = bui.app.config
|
||||
@ -292,7 +302,7 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
from bauiv1lib.confirm import ConfirmWindow
|
||||
|
||||
if (
|
||||
if REQUIRE_PRO and (
|
||||
bui.app.classic is not None
|
||||
and not bui.app.classic.accounts.have_pro_options()
|
||||
):
|
||||
@ -321,7 +331,7 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
|
||||
if (
|
||||
if REQUIRE_PRO and (
|
||||
bui.app.classic is not None
|
||||
and not bui.app.classic.accounts.have_pro_options()
|
||||
):
|
||||
@ -387,29 +397,30 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
music.music_types[bui.app.classic.MusicPlayMode.REGULAR]
|
||||
)
|
||||
|
||||
def _back(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.settings.audio import AudioSettingsWindow
|
||||
# def _back(self) -> None:
|
||||
# # pylint: disable=cyclic-import
|
||||
# from bauiv1lib.settings.audio import AudioSettingsWindow
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
# # no-op if our underlying widget is dead or on its way out.
|
||||
# if not self._root_widget or self._root_widget.transitioning_out:
|
||||
# return
|
||||
|
||||
self._save_state()
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, transition=self._transition_out
|
||||
)
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
AudioSettingsWindow(transition='in_left').get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
)
|
||||
# self._save_state()
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition=self._transition_out
|
||||
# )
|
||||
# assert bui.app.classic is not None
|
||||
# bui.app.ui_v1.set_main_window(
|
||||
# AudioSettingsWindow(transition='in_left'),
|
||||
# from_window=self,
|
||||
# is_back=True,
|
||||
# )
|
||||
|
||||
def _edit_soundtrack_with_sound(self) -> None:
|
||||
# pylint: disable=cyclic-import
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
|
||||
if (
|
||||
if REQUIRE_PRO and (
|
||||
bui.app.classic is not None
|
||||
and not bui.app.classic.accounts.have_pro_options()
|
||||
):
|
||||
@ -423,11 +434,15 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
from bauiv1lib.soundtrack.edit import SoundtrackEditWindow
|
||||
|
||||
if UNDER_CONSTRUCTION:
|
||||
bui.screenmessage('UNDER CONSTRUCTION')
|
||||
return
|
||||
|
||||
# no-op if our underlying widget is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
if (
|
||||
if REQUIRE_PRO and (
|
||||
bui.app.classic is not None
|
||||
and not bui.app.classic.accounts.have_pro_options()
|
||||
):
|
||||
@ -446,11 +461,9 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
assert bui.app.classic is not None
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
SoundtrackEditWindow(
|
||||
existing_soundtrack=self._selected_soundtrack
|
||||
).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
SoundtrackEditWindow(existing_soundtrack=self._selected_soundtrack),
|
||||
from_window=self,
|
||||
)
|
||||
|
||||
def _get_soundtrack_display_name(self, soundtrack: str) -> bui.Lstr:
|
||||
@ -541,7 +554,11 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
from bauiv1lib.purchase import PurchaseWindow
|
||||
from bauiv1lib.soundtrack.edit import SoundtrackEditWindow
|
||||
|
||||
if (
|
||||
if UNDER_CONSTRUCTION:
|
||||
bui.screenmessage('UNDER CONSTRUCTION')
|
||||
return
|
||||
|
||||
if REQUIRE_PRO and (
|
||||
bui.app.classic is not None
|
||||
and not bui.app.classic.accounts.have_pro_options()
|
||||
):
|
||||
@ -549,9 +566,8 @@ class SoundtrackBrowserWindow(bui.Window):
|
||||
return
|
||||
self._save_state()
|
||||
bui.containerwidget(edit=self._root_widget, transition='out_left')
|
||||
bui.app.ui_v1.set_main_menu_window(
|
||||
SoundtrackEditWindow(existing_soundtrack=None).get_root_widget(),
|
||||
from_window=self._root_widget,
|
||||
bui.app.ui_v1.set_main_window(
|
||||
SoundtrackEditWindow(existing_soundtrack=None), from_window=self
|
||||
)
|
||||
|
||||
def _create_done(self, new_soundtrack: str) -> None:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user