mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
wiring up inbox ui
This commit is contained in:
parent
8cbcfa771f
commit
fbf5d420d4
106
.efrocachemap
generated
106
.efrocachemap
generated
@ -421,44 +421,44 @@
|
||||
"build/assets/ba_data/audio/zoeOw.ogg": "b2d705c31c9dcc1efdc71394764c3beb",
|
||||
"build/assets/ba_data/audio/zoePickup01.ogg": "e9366dc2d2b8ab8b0c4e2c14c02d0789",
|
||||
"build/assets/ba_data/audio/zoeScream01.ogg": "903e0e45ee9b3373e9d9ce20c814374e",
|
||||
"build/assets/ba_data/data/langdata.json": "54a0a77dc0adb7ed5dd76cd175741fc7",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "4a6fc46285d6289ee14a7ccd9e801ac4",
|
||||
"build/assets/ba_data/data/langdata.json": "03810e5cca79c5fa092f47648060ca0f",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "8f89f09ad168c251765efebde4c9069c",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "1004e5ea10b8deaef517fd37e9309521",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "3c5e0a568008780f2e7258bf74b54efd",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "3a8ad6b99e13152872962019b3eef49d",
|
||||
"build/assets/ba_data/data/languages/chinesetraditional.json": "904b35b656c53f9830e406565edd5120",
|
||||
"build/assets/ba_data/data/languages/croatian.json": "1e541070309ff6be95b0c39940aa7e99",
|
||||
"build/assets/ba_data/data/languages/czech.json": "d18b7d1c6bf51fc81af4084ef0e69e3e",
|
||||
"build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "734357560f53b4820221f6d60a0b79e8",
|
||||
"build/assets/ba_data/data/languages/english.json": "dffc4a03b94c74f11da188a7c4187eda",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "f4e1e8e9231cda9d1bcc7e87a7f8821e",
|
||||
"build/assets/ba_data/data/languages/english.json": "b5917c3b975155e35fedb655dbd7568c",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "b5c8fb4f820bb3b521516321d51f4523",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "08b626ee9d8b66c55e79a4829c6cb9f2",
|
||||
"build/assets/ba_data/data/languages/french.json": "6d20655730b1017ef187fd828b91d43c",
|
||||
"build/assets/ba_data/data/languages/german.json": "c979cb1397d53a1e5b6c9a7becf83072",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "2efafa7c1d479ce1fa46e897739508e5",
|
||||
"build/assets/ba_data/data/languages/german.json": "a150dbb5c0f43984757f7db295d96203",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "df76e851aee59657b69e34efd54fee06",
|
||||
"build/assets/ba_data/data/languages/greek.json": "d28d1092fbb00ed857cbd53124c0dc78",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "5f60453c7dd3853c95c6f822e92d5300",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "567e6976b3c72f891431ad7fcc62ab16",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "9d88004a98f0fbe2ea72edd5e0b3002e",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "2ccb3fe081ead7706dbebb1008a8bc4e",
|
||||
"build/assets/ba_data/data/languages/italian.json": "3557cd4697da8c59ed33bda066e8cd93",
|
||||
"build/assets/ba_data/data/languages/italian.json": "43735ea42d14c121bc14eace16f904a2",
|
||||
"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": "2584895475fe62b3fe49a5ea5e69b4b1",
|
||||
"build/assets/ba_data/data/languages/piratespeak.json": "b9fe871e6331b7178cbacbf7eb3033aa",
|
||||
"build/assets/ba_data/data/languages/polish.json": "89333fb207f9eb2f22fff5a95b022c35",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "e1c4414fced051d2c1967417fd47650a",
|
||||
"build/assets/ba_data/data/languages/polish.json": "d0822d5d3bdd72ddb04dc3c43a0b1395",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "46649f4a8f3c5f69758e8b75ffacf439",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "5ae206fe0b71c4015b02b86da8931c8f",
|
||||
"build/assets/ba_data/data/languages/russian.json": "33c3943f1096aa37f9815d93c6ac1273",
|
||||
"build/assets/ba_data/data/languages/russian.json": "72bdbb27ede61bbfeafbf81fa4a19e45",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "623fa4129a1154c2f32ed7867e56ff6a",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "3c08c748c96c71bd9e1d7291fb8817b6",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "27f564597977b8764583a10d750900be",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "13f587058931acbb68a48981063ee5ff",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "3b179e7333183c70adb0811246b09959",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "ead39b864228696a9b0d19344bc4b5ec",
|
||||
"build/assets/ba_data/data/languages/thai.json": "383540a1e9c7c131ac579f51afc87471",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "9e8268786667aa3531593edb6ee66112",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "3a5b8132690fcd583d280879876c85b7",
|
||||
"build/assets/ba_data/data/languages/turkish.json": "440cb59e69ed689018c17d4be0fb4696",
|
||||
"build/assets/ba_data/data/languages/ukrainian.json": "6063d27c9d6ed013b2b64ff452433621",
|
||||
"build/assets/ba_data/data/languages/venetian.json": "abebcc38ca2655578e65428cc0dd3c45",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "34a8b75acba2c0234e0b00fb4ef7d011",
|
||||
"build/assets/ba_data/data/languages/vietnamese.json": "59f6686890ceac2b0ac92597751a18ca",
|
||||
"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",
|
||||
@ -4099,42 +4099,42 @@
|
||||
"build/assets/windows/Win32/ucrtbased.dll": "bfd1180c269d3950b76f35a63655e9e1",
|
||||
"build/assets/windows/Win32/vc_redist.x86.exe": "15a5f1f876503885adbdf5b3989b3718",
|
||||
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "c9c741a8c1908f709d9e69f95078e54d",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "48f6568ba24b78e376fcb0109d8811fa",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "74f4a7a42a51aab41baa0b06933ba90a",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "7c3305d87a435b8a2308faf9798af681",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "f10715043bcd264941d66e63b00bb171",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "701b28fdf672a88bdc85aac449a52933",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "a9b00364c83414d86b81e99e5d9e1b10",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "76e1077a37e919260846cfd96985bb3e",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "fd6c8276e03e6af24c897d974838dc34",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "d5c311bb092286d8ef7f48f51e7da95f",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "be9ae9fa1f04a87c4dfd319c02158b92",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "bd15c256a1dd4e086564b23055904a68",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "380d586848a9351eaff8da027b1d3aeb",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "352089e2917fef437e176e148f5fcd91",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "7667304055cd226341597c45534c812e",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "b323fe4cdd3b7d2f31f6e05db7bb04f3",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "e57cd21ff8c3566b1eb5fc9e79474d69",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "206f0407a6d912b292c6530cd969030b",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "e57cd21ff8c3566b1eb5fc9e79474d69",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "206f0407a6d912b292c6530cd969030b",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "6a891ea7e3609d5c30a3b321db59dc78",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "7f37a6249393fc422a536b3e1622b96f",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "6a891ea7e3609d5c30a3b321db59dc78",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "7f37a6249393fc422a536b3e1622b96f",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "209def6990e220110e5433581dad95e7",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "910f66cc0ddf5d17e751dc295f84e63e",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "209def6990e220110e5433581dad95e7",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "910f66cc0ddf5d17e751dc295f84e63e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "8cba3a66655dc40054d11acf13131226",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "a23295d8e71df2f8c308cfcd4b628827",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "72eaa6f4466fad2260c121711ec9ed09",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "c9748838494847186721a17dde8fd069",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "e41041e152263ae5552eb0e25c6ae8b8",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "a566b94b52cc4c281ada8a32a7fe078b",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "604c937543f27648e66217818cfc9714",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "d57aa1b54409ef038b2e86b1d59f9d26",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "4fef5a35efc6a2e74b6238ec87838be4",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "9ff03f147a4b5effc838bc2539c17227",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "455c1b9e6bba6db619756c25f6203b80",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "27ab3c363db144716d818003bd7a18f9",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "d9c645eb18380486349dd04f7fee4725",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "15606ae17b5d02daa4fbc6549e8f1290",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "fc798bac8c9e780695eabc930b605c2d",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "43a57614eb5df0c52ee8e64c3061d47d",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "7eec8b4ba4bb300f5f7389ca5a6abec3",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "5924800f1d7870bda557716722b2373b",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "0ab737966bf957046ca15121b1beafbb",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "f835b62e09a9933f5d4c98ba3c3195b1",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "7e2c3b108f358e5dcee152f7acbba90f",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "b2a7b275c79f8f8ea23b7ea1ec1bc3e6",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "1d17fe8c07b5ec076f799e4e758354a1",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "cb7eac5051dda9024db0076f7c7a0a64",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "678f8cbc0a31cf59f86211804f3d18f3",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "658a1267cf8454e74dd7a43d4921a862",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "678f8cbc0a31cf59f86211804f3d18f3",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "658a1267cf8454e74dd7a43d4921a862",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "5dfc9ffb40df78765dee25eed63b4d30",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "9c65f68f604202158a6c7486eeb985a9",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "5dfc9ffb40df78765dee25eed63b4d30",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "9c65f68f604202158a6c7486eeb985a9",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "4e5e0cac71feae718dfcccdeaa03eba1",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "c54e70ec873ecab76c655c20e13f595e",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "4e5e0cac71feae718dfcccdeaa03eba1",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "c54e70ec873ecab76c655c20e13f595e",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "131825eb39eb85e5231d1507cb03eee5",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "90f0217980b38b9068477208eff91a64",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "c7604ca233b96f41ee3d48e4d9841774",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "a8f0f4570ec807c71aa0aff1e9d02d40",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "9fb98011f0afe0231bbee6357be07d11",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "85cba33219b47db164d78d50b8b2edf5",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "7e72e3c500358123aae35a73a4060171",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "2476d7c95ae08ec0fb1662241fe27655",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "06042d31df0ff9af96b99477162e2a91",
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
### 1.7.37 (build 22123, api 9, 2024-12-03)
|
||||
### 1.7.37 (build 22125, api 9, 2024-12-06)
|
||||
- Bumping api version to 9. As you'll see below, there's some UI changes that
|
||||
will require a bit of work for any UI mods to adapt to. If your mods don't
|
||||
touch UI stuff at all you can simply bump your api version and call it a day.
|
||||
|
||||
@ -9,7 +9,7 @@ pur==7.3.2
|
||||
pylint==3.3.2
|
||||
pylsp-mypy==0.6.9
|
||||
pytest==8.3.4
|
||||
python-daemon==3.1.0
|
||||
python-daemon==3.1.2
|
||||
python-lsp-black==2.0.0
|
||||
python-lsp-server==1.12.0
|
||||
requests==2.32.3
|
||||
|
||||
@ -252,6 +252,14 @@ if TYPE_CHECKING:
|
||||
# type checking on both positional and keyword arguments (as of mypy
|
||||
# 1.11).
|
||||
|
||||
# FIXME: Actually, currently (as of Dec 2024) mypy doesn't fully
|
||||
# type check partial. The partial() call itself is checked, but the
|
||||
# resulting callable seems to be essentially untyped. We should
|
||||
# probably revise this stuff so that Call and WeakCall are for 100%
|
||||
# complete calls so we can fully type check them using ParamSpecs or
|
||||
# whatnot. We could then write a weak_partial() call if we actually
|
||||
# need that particular combination of functionality.
|
||||
|
||||
# Note: Something here is wonky with pylint, possibly related to our
|
||||
# custom pylint plugin. Disabling all checks seems to fix it.
|
||||
# pylint: disable=all
|
||||
|
||||
@ -205,6 +205,9 @@ class ClassicAppMode(babase.AppMode):
|
||||
self, val: bacommon.cloud.ClassicAccountLiveData
|
||||
) -> None:
|
||||
achp = round(val.achievements / max(val.achievements_total, 1) * 100.0)
|
||||
ibc = str(val.inbox_count)
|
||||
if val.inbox_count_is_max:
|
||||
ibc += '+'
|
||||
_baclassic.set_root_ui_values(
|
||||
tickets_text=str(val.tickets),
|
||||
tokens_text=str(val.tokens),
|
||||
@ -217,7 +220,7 @@ class ClassicAppMode(babase.AppMode):
|
||||
achievements_percent_text=f'{achp}%',
|
||||
level_text=str(val.level),
|
||||
xp_text=f'{val.xp}/{val.xpmax}',
|
||||
inbox_count_text=str(val.inbox_count),
|
||||
inbox_count_text=ibc,
|
||||
)
|
||||
|
||||
def _root_ui_menu_press(self) -> None:
|
||||
@ -372,13 +375,16 @@ class ClassicAppMode(babase.AppMode):
|
||||
)
|
||||
|
||||
def _root_ui_inbox_press(self) -> None:
|
||||
from bauiv1lib.connectivity import wait_for_connectivity
|
||||
from bauiv1lib.inbox import InboxWindow
|
||||
|
||||
self._auxiliary_window_nav(
|
||||
win_type=InboxWindow,
|
||||
win_create_call=lambda: InboxWindow(
|
||||
origin_widget=bauiv1.get_special_widget('inbox_button')
|
||||
),
|
||||
wait_for_connectivity(
|
||||
on_connected=lambda: self._auxiliary_window_nav(
|
||||
win_type=InboxWindow,
|
||||
win_create_call=lambda: InboxWindow(
|
||||
origin_widget=bauiv1.get_special_widget('inbox_button')
|
||||
),
|
||||
)
|
||||
)
|
||||
|
||||
def _root_ui_store_press(self) -> None:
|
||||
|
||||
@ -53,7 +53,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 22123
|
||||
TARGET_BALLISTICA_BUILD = 22125
|
||||
TARGET_BALLISTICA_VERSION = '1.7.37'
|
||||
|
||||
|
||||
|
||||
@ -117,6 +117,24 @@ class CloudSubsystem(babase.AppSubsystem):
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSInboxRequestMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSInboxRequestResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
@overload
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: bacommon.cloud.BSInboxEntryProcessMessage,
|
||||
on_response: Callable[
|
||||
[bacommon.cloud.BSInboxEntryProcessResponse | Exception], None
|
||||
],
|
||||
) -> None: ...
|
||||
|
||||
def send_message_cb(
|
||||
self,
|
||||
msg: Message,
|
||||
|
||||
@ -4,22 +4,53 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import weakref
|
||||
from dataclasses import dataclass
|
||||
from typing import override
|
||||
|
||||
# from bauiv1lib.popup import PopupWindow
|
||||
from efro.error import CommunicationError
|
||||
import bacommon.cloud
|
||||
import bauiv1 as bui
|
||||
|
||||
# Messages with format versions higher than this will show up as
|
||||
# 'app needs to be updated to view this'
|
||||
SUPPORTED_INBOX_MESSAGE_FORMAT_VERSION = 1
|
||||
|
||||
|
||||
@dataclass
|
||||
class _MessageEntry:
|
||||
type: bacommon.cloud.BSInboxEntryType
|
||||
id: str
|
||||
height: float
|
||||
text_height: float
|
||||
scale: float
|
||||
text: str
|
||||
color: tuple[float, float, float]
|
||||
backing: bui.Widget | None = None
|
||||
button_positive: bui.Widget | None = None
|
||||
button_negative: bui.Widget | None = None
|
||||
message_text: bui.Widget | None = None
|
||||
processing_complete: bool = False
|
||||
|
||||
|
||||
class InboxWindow(bui.MainWindow):
|
||||
"""Popup window to show account messages."""
|
||||
|
||||
def __del__(self) -> None:
|
||||
print('~InboxWindow()')
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
transition: str | None = 'in_right',
|
||||
origin_widget: bui.Widget | None = None,
|
||||
):
|
||||
|
||||
print('InboxWindow()')
|
||||
assert bui.app.classic is not None
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
|
||||
self._message_entries: list[_MessageEntry] = []
|
||||
|
||||
self._width = 600 if uiscale is bui.UIScale.SMALL else 450
|
||||
self._height = (
|
||||
380
|
||||
@ -83,7 +114,7 @@ class InboxWindow(bui.MainWindow):
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
scale=0.6,
|
||||
text='INBOX (UNDER CONSTRUCTION)',
|
||||
text=bui.Lstr(resource='inboxText'),
|
||||
maxwidth=200,
|
||||
color=bui.app.ui_v1.title_color,
|
||||
)
|
||||
@ -99,7 +130,9 @@ class InboxWindow(bui.MainWindow):
|
||||
(110 if uiscale is bui.UIScale.SMALL else 30) + yoffs,
|
||||
),
|
||||
capture_arrows=True,
|
||||
simple_culling_v=10,
|
||||
simple_culling_v=200,
|
||||
claims_left_right=True,
|
||||
claims_up_down=True,
|
||||
)
|
||||
bui.widget(edit=self._scrollwidget, autoselect=True)
|
||||
if uiscale is bui.UIScale.SMALL:
|
||||
@ -109,32 +142,21 @@ class InboxWindow(bui.MainWindow):
|
||||
)
|
||||
|
||||
bui.containerwidget(
|
||||
edit=self._root_widget, cancel_button=self._back_button
|
||||
edit=self._root_widget,
|
||||
cancel_button=self._back_button,
|
||||
single_depth=True,
|
||||
)
|
||||
|
||||
entries: list[str] = []
|
||||
incr = 20
|
||||
sub_width = self._width - 90
|
||||
sub_height = 40 + len(entries) * incr
|
||||
# Kick off request.
|
||||
plus = bui.app.plus
|
||||
if plus is None or plus.accounts.primary is None:
|
||||
self._error(bui.Lstr(resource='notSignedInText'))
|
||||
return
|
||||
|
||||
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',
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSInboxRequestMessage(),
|
||||
on_response=bui.WeakCall(self._on_inbox_request_response),
|
||||
)
|
||||
|
||||
@override
|
||||
@ -147,16 +169,385 @@ class InboxWindow(bui.MainWindow):
|
||||
)
|
||||
)
|
||||
|
||||
# def _on_cancel_press(self) -> None:
|
||||
# self._transition_out()
|
||||
def _error(self, errmsg: bui.Lstr | str) -> None:
|
||||
"""Put ourself in a permanent error state."""
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.5),
|
||||
maxwidth=self._width * 0.7,
|
||||
scale=1.0,
|
||||
flatness=1.0,
|
||||
color=(1, 0, 0),
|
||||
shadow=0.0,
|
||||
text=errmsg,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
|
||||
# def _transition_out(self) -> None:
|
||||
# if not self._transitioning_out:
|
||||
# self._transitioning_out = True
|
||||
# bui.containerwidget(
|
||||
# edit=self._root_widget, transition='out_scale')
|
||||
def _on_message_entry_press(
|
||||
self,
|
||||
entry_weak: weakref.ReferenceType[_MessageEntry],
|
||||
process_type: bacommon.cloud.BSInboxEntryProcessType,
|
||||
) -> None:
|
||||
entry = entry_weak()
|
||||
if entry is None:
|
||||
return
|
||||
|
||||
# @override
|
||||
# def on_popup_cancel(self) -> None:
|
||||
# bui.getsound('swish').play()
|
||||
# self._transition_out()
|
||||
self._neuter_message_entry(entry)
|
||||
|
||||
# We don't do anything for invalid messages.
|
||||
if entry.type is bacommon.cloud.BSInboxEntryType.UNKNOWN:
|
||||
entry.processing_complete = True
|
||||
self._close_soon_if_all_processed()
|
||||
return
|
||||
|
||||
# Error if we're somehow signed out now.
|
||||
plus = bui.app.plus
|
||||
if plus is None or plus.accounts.primary is None:
|
||||
bui.screenmessage(
|
||||
bui.Lstr(resource='notSignedInText'), color=(1, 0, 0)
|
||||
)
|
||||
bui.getsound('error').play()
|
||||
return
|
||||
|
||||
# Message the master-server to process the entry.
|
||||
with plus.accounts.primary:
|
||||
plus.cloud.send_message_cb(
|
||||
bacommon.cloud.BSInboxEntryProcessMessage(
|
||||
entry.id, process_type
|
||||
),
|
||||
on_response=bui.WeakCall(
|
||||
self._on_inbox_entry_process_response,
|
||||
entry_weak,
|
||||
process_type,
|
||||
),
|
||||
)
|
||||
|
||||
# Tweak the button to show this is in progress.
|
||||
button = (
|
||||
entry.button_positive
|
||||
if process_type is bacommon.cloud.BSInboxEntryProcessType.POSITIVE
|
||||
else entry.button_negative
|
||||
)
|
||||
if button is not None:
|
||||
bui.buttonwidget(edit=button, label='...')
|
||||
|
||||
def _close_soon_if_all_processed(self) -> None:
|
||||
bui.apptimer(0.25, bui.WeakCall(self._close_if_all_processed))
|
||||
|
||||
def _close_if_all_processed(self) -> None:
|
||||
if not all(m.processing_complete for m in self._message_entries):
|
||||
return
|
||||
|
||||
self.main_window_back()
|
||||
|
||||
def _neuter_message_entry(self, entry: _MessageEntry) -> None:
|
||||
errsound = bui.getsound('error')
|
||||
if entry.button_positive is not None:
|
||||
bui.buttonwidget(
|
||||
edit=entry.button_positive,
|
||||
color=(0.5, 0.5, 0.5),
|
||||
textcolor=(0.4, 0.4, 0.4),
|
||||
on_activate_call=errsound.play,
|
||||
)
|
||||
if entry.button_negative is not None:
|
||||
bui.buttonwidget(
|
||||
edit=entry.button_negative,
|
||||
color=(0.5, 0.5, 0.5),
|
||||
textcolor=(0.4, 0.4, 0.4),
|
||||
on_activate_call=errsound.play,
|
||||
)
|
||||
if entry.backing is not None:
|
||||
bui.imagewidget(edit=entry.backing, color=(0.4, 0.4, 0.4))
|
||||
if entry.message_text is not None:
|
||||
bui.textwidget(edit=entry.message_text, color=(0.5, 0.5, 0.5, 0.5))
|
||||
|
||||
def _on_inbox_entry_process_response(
|
||||
self,
|
||||
entry_weak: weakref.ReferenceType[_MessageEntry],
|
||||
process_type: bacommon.cloud.BSInboxEntryProcessType,
|
||||
response: bacommon.cloud.BSInboxEntryProcessResponse | Exception,
|
||||
) -> None:
|
||||
entry = entry_weak()
|
||||
if entry is None:
|
||||
return
|
||||
|
||||
assert not entry.processing_complete
|
||||
entry.processing_complete = True
|
||||
self._close_soon_if_all_processed()
|
||||
|
||||
# No-op if our UI is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
# Tweak the button to show results.
|
||||
button = (
|
||||
entry.button_positive
|
||||
if process_type is bacommon.cloud.BSInboxEntryProcessType.POSITIVE
|
||||
else entry.button_negative
|
||||
)
|
||||
|
||||
# See if we should show an error message.
|
||||
if isinstance(response, Exception):
|
||||
if isinstance(response, CommunicationError):
|
||||
error_message = bui.Lstr(
|
||||
resource='internal.unavailableNoConnectionText'
|
||||
)
|
||||
else:
|
||||
error_message = bui.Lstr(resource='errorText')
|
||||
elif response.error is not None:
|
||||
error_message = bui.Lstr(
|
||||
translate=('serverResponses', response.error)
|
||||
)
|
||||
else:
|
||||
error_message = None
|
||||
|
||||
# Show error message if so.
|
||||
if error_message is not None:
|
||||
bui.screenmessage(error_message, color=(1, 0, 0))
|
||||
bui.getsound('error').play()
|
||||
if button is not None:
|
||||
bui.buttonwidget(
|
||||
edit=button, label=bui.Lstr(resource='errorText')
|
||||
)
|
||||
return
|
||||
|
||||
# Whee; no error. Mark as done.
|
||||
if button is not None:
|
||||
bui.buttonwidget(edit=button, label=bui.Lstr(resource='doneText'))
|
||||
|
||||
def _on_inbox_request_response(
|
||||
self, response: bacommon.cloud.BSInboxRequestResponse | Exception
|
||||
) -> None:
|
||||
# pylint: disable=too-many-locals
|
||||
# pylint: disable=too-many-statements
|
||||
# pylint: disable=too-many-branches
|
||||
|
||||
# No-op if our UI is dead or on its way out.
|
||||
if not self._root_widget or self._root_widget.transitioning_out:
|
||||
return
|
||||
|
||||
errmsg: str | bui.Lstr
|
||||
if isinstance(response, Exception):
|
||||
errmsg = bui.Lstr(resource='internal.unavailableNoConnectionText')
|
||||
is_error = True
|
||||
else:
|
||||
is_error = response.error is not None
|
||||
errmsg = (
|
||||
''
|
||||
if response.error is None
|
||||
else bui.Lstr(translate=('serverResponses', response.error))
|
||||
)
|
||||
|
||||
if is_error:
|
||||
self._error(errmsg)
|
||||
return
|
||||
|
||||
assert isinstance(response, bacommon.cloud.BSInboxRequestResponse)
|
||||
|
||||
# If we got no messages, don't touch anything. This keeps
|
||||
# keyboard control working in the empty case.
|
||||
if not response.entries:
|
||||
bui.textwidget(
|
||||
parent=self._root_widget,
|
||||
position=(self._width * 0.5, self._height * 0.5),
|
||||
maxwidth=self._width * 0.7,
|
||||
scale=1.0,
|
||||
flatness=1.0,
|
||||
color=(0.4, 0.4, 0.4),
|
||||
shadow=0.0,
|
||||
text=bui.Lstr(resource='noMessagesText'),
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
return
|
||||
|
||||
sub_width = self._width - 90
|
||||
sub_height = 0.0
|
||||
|
||||
# Run the math on row heights/etc.
|
||||
for i, entry in enumerate(response.entries):
|
||||
# We need to flatten text here so we can measure it.
|
||||
textfin: str
|
||||
color: tuple[float, float, float]
|
||||
|
||||
# Messages with either newer formatting or unrecognized
|
||||
# types show up as 'upgrade your app to see this'.
|
||||
if (
|
||||
entry.format_version > SUPPORTED_INBOX_MESSAGE_FORMAT_VERSION
|
||||
or entry.type is bacommon.cloud.BSInboxEntryType.UNKNOWN
|
||||
):
|
||||
textfin = bui.Lstr(
|
||||
translate=(
|
||||
'serverResponses',
|
||||
'You must update the app to view this.',
|
||||
)
|
||||
).evaluate()
|
||||
color = (0.6, 0.6, 0.6)
|
||||
else:
|
||||
# Translate raw response and apply any replacements.
|
||||
textfin = bui.Lstr(
|
||||
translate=('serverResponses', entry.message)
|
||||
).evaluate()
|
||||
assert len(entry.subs) % 2 == 0 # Should always be even.
|
||||
for j in range(0, len(entry.subs) - 1, 2):
|
||||
textfin = textfin.replace(entry.subs[j], entry.subs[j + 1])
|
||||
color = (0.55, 0.5, 0.7)
|
||||
|
||||
# Calc scale to fit width and then see what height we need
|
||||
# at that scale.
|
||||
t_width = max(
|
||||
10.0, bui.get_string_width(textfin, suppress_warning=True)
|
||||
)
|
||||
scale = min(0.6, (sub_width * 0.9) / t_width)
|
||||
t_height = (
|
||||
max(10.0, bui.get_string_height(textfin, suppress_warning=True))
|
||||
* scale
|
||||
)
|
||||
entry_height = 90.0 + t_height
|
||||
self._message_entries.append(
|
||||
_MessageEntry(
|
||||
type=entry.type,
|
||||
id=entry.id,
|
||||
height=entry_height,
|
||||
text_height=t_height,
|
||||
scale=scale,
|
||||
text=textfin,
|
||||
color=color,
|
||||
)
|
||||
)
|
||||
sub_height += entry_height
|
||||
|
||||
subcontainer = bui.containerwidget(
|
||||
id='inboxsub',
|
||||
parent=self._scrollwidget,
|
||||
size=(sub_width, sub_height),
|
||||
background=False,
|
||||
single_depth=True,
|
||||
claims_left_right=True,
|
||||
claims_up_down=True,
|
||||
)
|
||||
|
||||
backing_tex = bui.gettexture('buttonSquareWide')
|
||||
|
||||
buttonrows: list[list[bui.Widget]] = []
|
||||
y = sub_height
|
||||
for i, _entry in enumerate(response.entries):
|
||||
message_entry = self._message_entries[i]
|
||||
message_entry_weak = weakref.ref(message_entry)
|
||||
bwidth = 140
|
||||
bheight = 40
|
||||
|
||||
# Backing.
|
||||
message_entry.backing = img = bui.imagewidget(
|
||||
parent=subcontainer,
|
||||
position=(-0.022 * sub_width, y - message_entry.height * 1.09),
|
||||
texture=backing_tex,
|
||||
size=(sub_width * 1.07, message_entry.height * 1.15),
|
||||
color=message_entry.color,
|
||||
opacity=0.9,
|
||||
)
|
||||
bui.widget(edit=img, depth_range=(0, 0.1))
|
||||
|
||||
buttonrow: list[bui.Widget] = []
|
||||
have_negative_button = (
|
||||
message_entry.type
|
||||
is bacommon.cloud.BSInboxEntryType.CLAIM_DISCARD
|
||||
)
|
||||
|
||||
message_entry.button_positive = btn = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
(
|
||||
(sub_width - bwidth - 25)
|
||||
if have_negative_button
|
||||
else ((sub_width - bwidth) * 0.5)
|
||||
),
|
||||
y - message_entry.height + 15.0,
|
||||
),
|
||||
size=(bwidth, bheight),
|
||||
label=bui.Lstr(
|
||||
resource=(
|
||||
'claimText'
|
||||
if message_entry.type
|
||||
in {
|
||||
bacommon.cloud.BSInboxEntryType.CLAIM,
|
||||
bacommon.cloud.BSInboxEntryType.CLAIM_DISCARD,
|
||||
}
|
||||
else 'okText'
|
||||
)
|
||||
),
|
||||
color=message_entry.color,
|
||||
textcolor=(0, 1, 0),
|
||||
on_activate_call=bui.WeakCall(
|
||||
self._on_message_entry_press,
|
||||
message_entry_weak,
|
||||
bacommon.cloud.BSInboxEntryProcessType.POSITIVE,
|
||||
),
|
||||
)
|
||||
bui.widget(edit=btn, depth_range=(0.1, 1.0))
|
||||
buttonrow.append(btn)
|
||||
|
||||
if have_negative_button:
|
||||
message_entry.button_negative = btn2 = bui.buttonwidget(
|
||||
parent=subcontainer,
|
||||
position=(25, y - message_entry.height + 15.0),
|
||||
size=(bwidth, bheight),
|
||||
label=bui.Lstr(resource='discardText'),
|
||||
color=(0.85, 0.5, 0.7),
|
||||
textcolor=(1, 0.4, 0.4),
|
||||
on_activate_call=bui.WeakCall(
|
||||
self._on_message_entry_press,
|
||||
message_entry_weak,
|
||||
bacommon.cloud.BSInboxEntryProcessType.NEGATIVE,
|
||||
),
|
||||
)
|
||||
bui.widget(edit=btn2, depth_range=(0.1, 1.0))
|
||||
buttonrow.append(btn2)
|
||||
|
||||
buttonrows.append(buttonrow)
|
||||
|
||||
message_entry.message_text = bui.textwidget(
|
||||
parent=subcontainer,
|
||||
position=(
|
||||
sub_width * 0.5,
|
||||
y - message_entry.text_height * 0.5 - 23.0,
|
||||
),
|
||||
scale=message_entry.scale,
|
||||
flatness=1.0,
|
||||
shadow=0.0,
|
||||
text=message_entry.text,
|
||||
size=(0, 0),
|
||||
h_align='center',
|
||||
v_align='center',
|
||||
)
|
||||
y -= message_entry.height
|
||||
|
||||
uiscale = bui.app.ui_v1.uiscale
|
||||
above_widget = (
|
||||
bui.get_special_widget('back_button')
|
||||
if uiscale is bui.UIScale.SMALL
|
||||
else self._back_button
|
||||
)
|
||||
assert above_widget is not None
|
||||
for i, buttons in enumerate(buttonrows):
|
||||
if i < len(buttonrows) - 1:
|
||||
below_widget = buttonrows[i + 1][0]
|
||||
else:
|
||||
below_widget = None
|
||||
|
||||
assert buttons # We should never have an empty row.
|
||||
for j, button in enumerate(buttons):
|
||||
bui.widget(
|
||||
edit=button,
|
||||
up_widget=above_widget,
|
||||
down_widget=(
|
||||
button if below_widget is None else below_widget
|
||||
),
|
||||
right_widget=buttons[max(j - 1, 0)],
|
||||
left_widget=buttons[min(j + 1, len(buttons) - 1)],
|
||||
)
|
||||
|
||||
above_widget = buttons[0]
|
||||
|
||||
@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
|
||||
namespace ballistica {
|
||||
|
||||
// These are set automatically via script; don't modify them here.
|
||||
const int kEngineBuildNumber = 22123;
|
||||
const int kEngineBuildNumber = 22125;
|
||||
const char* kEngineVersion = "1.7.37";
|
||||
const int kEngineApiVersion = 9;
|
||||
|
||||
|
||||
@ -1115,6 +1115,7 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
PyObject* click_activate_obj{Py_None};
|
||||
PyObject* always_highlight_obj{Py_None};
|
||||
PyObject* parent_obj{Py_None};
|
||||
PyObject* id_obj{Py_None};
|
||||
ContainerWidget* parent_widget;
|
||||
PyObject* edit_obj{Py_None};
|
||||
PyObject* selectable_obj{Py_None};
|
||||
@ -1124,6 +1125,7 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
|
||||
static const char* kwlist[] = {"edit",
|
||||
"parent",
|
||||
"id",
|
||||
"size",
|
||||
"position",
|
||||
"background",
|
||||
@ -1156,16 +1158,16 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
nullptr};
|
||||
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, keywds, "|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
|
||||
const_cast<char**>(kwlist), &edit_obj, &parent_obj, &size_obj,
|
||||
&pos_obj, &background_obj, &selected_child_obj, &transition_obj,
|
||||
&cancel_button_obj, &start_button_obj, &root_selectable_obj,
|
||||
&on_activate_call_obj, &claims_left_right_obj, &claims_tab_obj,
|
||||
&selection_loops_obj, &selection_loops_to_parent_obj, &scale_obj,
|
||||
&on_outside_click_call_obj, &single_depth_obj, &visible_child_obj,
|
||||
&stack_offset_obj, &color_obj, &on_cancel_call_obj,
|
||||
&print_list_exit_instructions_obj, &click_activate_obj,
|
||||
&always_highlight_obj, &selectable_obj,
|
||||
args, keywds, "|OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO",
|
||||
const_cast<char**>(kwlist), &edit_obj, &parent_obj, &id_obj,
|
||||
&size_obj, &pos_obj, &background_obj, &selected_child_obj,
|
||||
&transition_obj, &cancel_button_obj, &start_button_obj,
|
||||
&root_selectable_obj, &on_activate_call_obj, &claims_left_right_obj,
|
||||
&claims_tab_obj, &selection_loops_obj, &selection_loops_to_parent_obj,
|
||||
&scale_obj, &on_outside_click_call_obj, &single_depth_obj,
|
||||
&visible_child_obj, &stack_offset_obj, &color_obj,
|
||||
&on_cancel_call_obj, &print_list_exit_instructions_obj,
|
||||
&click_activate_obj, &always_highlight_obj, &selectable_obj,
|
||||
&scale_origin_stack_offset_obj, &toolbar_visibility_obj,
|
||||
&on_select_call_obj, &claim_outside_clicks_obj,
|
||||
&claims_up_down_obj)) {
|
||||
@ -1187,6 +1189,9 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
throw Exception("Invalid or nonexistent widget.",
|
||||
PyExcType::kWidgetNotFound);
|
||||
}
|
||||
if (id_obj != Py_None) {
|
||||
throw Exception("ID can only be set when creating.");
|
||||
}
|
||||
} else {
|
||||
if (parent_obj == Py_None) {
|
||||
BA_PRECONDITION(g_ui_v1 && g_ui_v1->screen_root_widget() != nullptr);
|
||||
@ -1200,6 +1205,12 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
PyExcType::kWidgetNotFound);
|
||||
}
|
||||
widget = Object::New<ContainerWidget>();
|
||||
|
||||
// Id needs to be set before adding to parent.
|
||||
if (id_obj != Py_None) {
|
||||
widget->set_id(Python::GetPyString(id_obj));
|
||||
}
|
||||
|
||||
g_ui_v1->AddWidget(widget.get(), parent_widget);
|
||||
}
|
||||
|
||||
@ -1386,6 +1397,7 @@ static PyMethodDef PyContainerWidgetDef = {
|
||||
"containerwidget(*,\n"
|
||||
" edit: bauiv1.Widget | None = None,\n"
|
||||
" parent: bauiv1.Widget | None = None,\n"
|
||||
" id: str | None = None,\n"
|
||||
" size: Sequence[float] | None = None,\n"
|
||||
" position: Sequence[float] | None = None,\n"
|
||||
" background: bool | None = None,\n"
|
||||
@ -2347,6 +2359,7 @@ static auto PyWidgetCall(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
PyObject* show_buffer_bottom_obj{Py_None};
|
||||
PyObject* show_buffer_left_obj{Py_None};
|
||||
PyObject* show_buffer_right_obj{Py_None};
|
||||
PyObject* depth_range_obj{Py_None};
|
||||
PyObject* autoselect_obj{Py_None};
|
||||
|
||||
static const char* kwlist[] = {"edit",
|
||||
@ -2358,13 +2371,14 @@ static auto PyWidgetCall(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
"show_buffer_bottom",
|
||||
"show_buffer_left",
|
||||
"show_buffer_right",
|
||||
"depth_range",
|
||||
"autoselect",
|
||||
nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(
|
||||
args, keywds, "O|OOOOOOOOO", const_cast<char**>(kwlist), &edit_obj,
|
||||
args, keywds, "O|OOOOOOOOOO", const_cast<char**>(kwlist), &edit_obj,
|
||||
&up_widget_obj, &down_widget_obj, &left_widget_obj, &right_widget_obj,
|
||||
&show_buffer_top_obj, &show_buffer_bottom_obj, &show_buffer_left_obj,
|
||||
&show_buffer_right_obj, &autoselect_obj))
|
||||
&show_buffer_right_obj, &depth_range_obj, &autoselect_obj))
|
||||
return nullptr;
|
||||
|
||||
if (!g_base->CurrentContext().IsEmpty()) {
|
||||
@ -2424,6 +2438,21 @@ static auto PyWidgetCall(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
if (show_buffer_right_obj != Py_None) {
|
||||
widget->set_show_buffer_right(Python::GetPyFloat(show_buffer_right_obj));
|
||||
}
|
||||
if (depth_range_obj != Py_None) {
|
||||
auto depth_range = Python::GetPyFloats(depth_range_obj);
|
||||
if (depth_range.size() != 2) {
|
||||
throw Exception("Expected 2 float values.", PyExcType::kValue);
|
||||
}
|
||||
if (depth_range[0] < 0.0 || depth_range[1] > 1.0
|
||||
|| depth_range[1] <= depth_range[0]) {
|
||||
throw Exception(
|
||||
"Invalid depth range values;"
|
||||
" values must be between 0 and 1 and second value must be larger "
|
||||
"than first.",
|
||||
PyExcType::kValue);
|
||||
}
|
||||
widget->set_depth_range(depth_range[0], depth_range[1]);
|
||||
}
|
||||
if (autoselect_obj != Py_None) {
|
||||
widget->set_auto_select(Python::GetPyBool(autoselect_obj));
|
||||
}
|
||||
@ -2450,6 +2479,7 @@ static PyMethodDef PyWidgetDef = {
|
||||
" show_buffer_bottom: float | None = None,\n"
|
||||
" show_buffer_left: float | None = None,\n"
|
||||
" show_buffer_right: float | None = None,\n"
|
||||
" depth_range: tuple[float, float] | None = None,\n"
|
||||
" autoselect: bool | None = None) -> None\n"
|
||||
"\n"
|
||||
"Edit common attributes of any widget.\n"
|
||||
|
||||
@ -61,18 +61,18 @@ void ContainerWidget::DrawChildren(base::RenderPass* pass,
|
||||
|
||||
// We're expected to fill z space 0..1 when we draw... so we need to divide
|
||||
// that space between our child widgets plus our bg layer.
|
||||
float layer_thickness = 0.0f;
|
||||
float layer_spacing = 0.0f;
|
||||
float base_offset = 0.0f;
|
||||
float layer_thickness1 = 0.0f;
|
||||
float layer_thickness2 = 0.0f;
|
||||
float layer_thickness3 = 0.0f;
|
||||
float layer_spacing1 = 0.0f;
|
||||
float layer_spacing2 = 0.0f;
|
||||
float layer_spacing3 = 0.0f;
|
||||
float base_offset1 = 0.0f;
|
||||
float base_offset2 = 0.0f;
|
||||
float base_offset3 = 0.0f;
|
||||
float layer_thickness{};
|
||||
float layer_spacing{};
|
||||
float base_offset{};
|
||||
float layer_thickness1{};
|
||||
float layer_thickness2{};
|
||||
float layer_thickness3{};
|
||||
float layer_spacing1{};
|
||||
float layer_spacing2{};
|
||||
float layer_spacing3{};
|
||||
float base_offset1{};
|
||||
float base_offset2{};
|
||||
float base_offset3{};
|
||||
|
||||
// In single-depth mode we draw all widgets at the same depth so they each get
|
||||
// our full depth resolution. however they may overlap incorrectly.
|
||||
@ -203,12 +203,17 @@ void ContainerWidget::DrawChildren(base::RenderPass* pass,
|
||||
// Widgets can opt to use a subset of their allotted depth slice.
|
||||
float d_min = w.depth_range_min();
|
||||
float d_max = w.depth_range_max();
|
||||
float this_z_offs;
|
||||
float this_layer_thickness;
|
||||
if (d_min != 0.0f || d_max != 1.0f) {
|
||||
z_offs += layer_thickness * d_min;
|
||||
layer_thickness *= (d_max - d_min);
|
||||
this_z_offs = z_offs + layer_thickness * d_min;
|
||||
this_layer_thickness = layer_thickness * (d_max - d_min);
|
||||
} else {
|
||||
this_z_offs = z_offs;
|
||||
this_layer_thickness = layer_thickness;
|
||||
}
|
||||
c.Translate(x_offset + tx, y_offset + ty, z_offs);
|
||||
c.Scale(s, s, layer_thickness);
|
||||
c.Translate(x_offset + tx, y_offset + ty, this_z_offs);
|
||||
c.Scale(s, s, this_layer_thickness);
|
||||
c.Submit();
|
||||
w.Draw(pass, draw_transparent);
|
||||
}
|
||||
@ -276,12 +281,17 @@ void ContainerWidget::DrawChildren(base::RenderPass* pass,
|
||||
// Widgets can opt to use a subset of their allotted depth slice.
|
||||
float d_min = w.depth_range_min();
|
||||
float d_max = w.depth_range_max();
|
||||
float this_z_offs;
|
||||
float this_layer_thickness;
|
||||
if (d_min != 0.0f || d_max != 1.0f) {
|
||||
z_offs += layer_thickness * d_min;
|
||||
layer_thickness *= (d_max - d_min);
|
||||
this_z_offs = z_offs + layer_thickness * d_min;
|
||||
this_layer_thickness = layer_thickness * (d_max - d_min);
|
||||
} else {
|
||||
this_z_offs = z_offs;
|
||||
this_layer_thickness = layer_thickness;
|
||||
}
|
||||
c.Translate(x_offset + tx, y_offset + ty, z_offs);
|
||||
c.Scale(s, s, layer_thickness);
|
||||
c.Translate(x_offset + tx, y_offset + ty, this_z_offs);
|
||||
c.Scale(s, s, this_layer_thickness);
|
||||
c.Submit();
|
||||
w.Draw(pass, draw_transparent);
|
||||
}
|
||||
|
||||
@ -3,9 +3,11 @@
|
||||
"""Functionality related to cloud functionality."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import datetime
|
||||
from enum import Enum
|
||||
from dataclasses import dataclass, field
|
||||
from typing import TYPE_CHECKING, Annotated, override
|
||||
from enum import Enum
|
||||
|
||||
from efro.message import Message, Response
|
||||
from efro.dataclassio import ioprepped, IOAttrs
|
||||
@ -355,3 +357,85 @@ class ClassicAccountLiveData:
|
||||
xpmax: Annotated[int, IOAttrs('xpm')]
|
||||
|
||||
inbox_count: Annotated[int, IOAttrs('ibc')]
|
||||
inbox_count_is_max: Annotated[bool, IOAttrs('ibcm')]
|
||||
|
||||
|
||||
class BSInboxEntryType(Enum):
|
||||
"""Types of entries that can be in an inbox."""
|
||||
|
||||
UNKNOWN = 'u' # Entry types we don't support will be this.
|
||||
SIMPLE = 's'
|
||||
CLAIM = 'c'
|
||||
CLAIM_DISCARD = 'cd'
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSInboxEntry:
|
||||
"""Single message in an inbox."""
|
||||
|
||||
type: Annotated[
|
||||
BSInboxEntryType, IOAttrs('t', enum_fallback=BSInboxEntryType.UNKNOWN)
|
||||
]
|
||||
id: Annotated[str, IOAttrs('i')]
|
||||
createtime: Annotated[datetime.datetime, IOAttrs('c')]
|
||||
|
||||
# If clients don't support format_version of a message they will
|
||||
# display 'app needs to be updated to show this'.
|
||||
format_version: Annotated[int, IOAttrs('f', soft_default=1)]
|
||||
|
||||
# These have soft defaults so can be removed in the future if desired.
|
||||
message: Annotated[str, IOAttrs('m', soft_default='(invalid message)')]
|
||||
subs: Annotated[list[str], IOAttrs('s', soft_default_factory=list)]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSInboxRequestMessage(Message):
|
||||
"""Message requesting our inbox."""
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [BSInboxRequestResponse]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSInboxRequestResponse(Response):
|
||||
"""Here's that inbox contents you asked for, boss."""
|
||||
|
||||
entries: Annotated[list[BSInboxEntry], IOAttrs('m')]
|
||||
|
||||
# Printable error if something goes wrong.
|
||||
error: Annotated[str | None, IOAttrs('e')] = None
|
||||
|
||||
|
||||
class BSInboxEntryProcessType(Enum):
|
||||
"""Types of processing we can ask for."""
|
||||
|
||||
POSITIVE = 'p'
|
||||
NEGATIVE = 'n'
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSInboxEntryProcessMessage(Message):
|
||||
"""Do something to an inbox entry."""
|
||||
|
||||
id: Annotated[str, IOAttrs('i')]
|
||||
process_type: Annotated[BSInboxEntryProcessType, IOAttrs('t')]
|
||||
|
||||
@override
|
||||
@classmethod
|
||||
def get_response_types(cls) -> list[type[Response] | None]:
|
||||
return [BSInboxEntryProcessResponse]
|
||||
|
||||
|
||||
@ioprepped
|
||||
@dataclass
|
||||
class BSInboxEntryProcessResponse(Response):
|
||||
"""Did something to that inbox entry, boss."""
|
||||
|
||||
# Printable error if something goes wrong.
|
||||
error: Annotated[str | None, IOAttrs('e')] = None
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user