mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-19 13:25:31 +08:00
added on-screen dev-console button option under advanced settings
This commit is contained in:
parent
cd098866ea
commit
58cec911a6
100
.efrocachemap
generated
100
.efrocachemap
generated
@ -421,7 +421,7 @@
|
||||
"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": "7be961f6a6b9742859638cbd5a747e18",
|
||||
"build/assets/ba_data/data/langdata.json": "0f4630cc7c78222e782da9cedd4df284",
|
||||
"build/assets/ba_data/data/languages/arabic.json": "db961f7fe0541a31880929e1c17ea957",
|
||||
"build/assets/ba_data/data/languages/belarussian.json": "5e373ddcfa6e1f771b74c02298a6599a",
|
||||
"build/assets/ba_data/data/languages/chinese.json": "6520f793066c95773002b4e9a920fd1d",
|
||||
@ -430,27 +430,27 @@
|
||||
"build/assets/ba_data/data/languages/czech.json": "f3ce219840946cb8f9aa6d3e25927ab3",
|
||||
"build/assets/ba_data/data/languages/danish.json": "3fd69080783d5c9dcc0af737f02b6f1e",
|
||||
"build/assets/ba_data/data/languages/dutch.json": "22b44a33bf81142ba2befad14eb5746e",
|
||||
"build/assets/ba_data/data/languages/english.json": "d16e8899211693c20d3b00fc198f58c6",
|
||||
"build/assets/ba_data/data/languages/english.json": "6d261a19b40a27eca92f6199a26f5779",
|
||||
"build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880",
|
||||
"build/assets/ba_data/data/languages/filipino.json": "58f363cfd8a3ccf0c904ab753d95789b",
|
||||
"build/assets/ba_data/data/languages/french.json": "6057b18878ad8379e51b507fa94958d8",
|
||||
"build/assets/ba_data/data/languages/german.json": "549754d2a530d825200c6126be56df5c",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "236f8547ba09722b7c7f5b8333986984",
|
||||
"build/assets/ba_data/data/languages/gibberish.json": "d23fe0936bb6177443f4b74bf5981b13",
|
||||
"build/assets/ba_data/data/languages/greek.json": "a65d78f912e9a89f98de004405167a6a",
|
||||
"build/assets/ba_data/data/languages/hindi.json": "88ee0cda537bab9ac827def5e236fe1a",
|
||||
"build/assets/ba_data/data/languages/hungarian.json": "796a290a8c44a1e7635208c2ff5fdc6e",
|
||||
"build/assets/ba_data/data/languages/indonesian.json": "583bae1ecc04375cee089a82359110b7",
|
||||
"build/assets/ba_data/data/languages/italian.json": "ce99027a5d1af17689b4311eafa5ff24",
|
||||
"build/assets/ba_data/data/languages/italian.json": "8d9332d461fa5b84780818bf6c2978b5",
|
||||
"build/assets/ba_data/data/languages/korean.json": "ca1122a9ee551da3f75ae632012bd0e2",
|
||||
"build/assets/ba_data/data/languages/malay.json": "832562ce997fc70704b9234c95fb2e38",
|
||||
"build/assets/ba_data/data/languages/persian.json": "5119aec9cbb2f8d00f2afaccf5fd5410",
|
||||
"build/assets/ba_data/data/languages/polish.json": "336eeb0028af5f3c7b9c12d3a051db2c",
|
||||
"build/assets/ba_data/data/languages/polish.json": "826c5b0402c2f0bcc29bc6f48b833545",
|
||||
"build/assets/ba_data/data/languages/portuguese.json": "99b27c598c90fd522132af3536aef0ee",
|
||||
"build/assets/ba_data/data/languages/romanian.json": "aeebdd54f65939c2facc6ac50c117826",
|
||||
"build/assets/ba_data/data/languages/russian.json": "aa99f9f597787fe4e09c8ab53fe2e081",
|
||||
"build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69",
|
||||
"build/assets/ba_data/data/languages/slovak.json": "27962d53dc3f7dd4e877cd40faafeeef",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "90d7408d07d9445630aecbe7efaa722d",
|
||||
"build/assets/ba_data/data/languages/spanish.json": "b5390c76f3475c8b6dd64ab9f170b4d8",
|
||||
"build/assets/ba_data/data/languages/swedish.json": "77d671f10613291ebf9c71da66f18a18",
|
||||
"build/assets/ba_data/data/languages/tamil.json": "b9d4b4e107456ea6420ee0f9d9d7a03e",
|
||||
"build/assets/ba_data/data/languages/thai.json": "33f63753c9af9a5b238d229a0bf23fbc",
|
||||
@ -4064,50 +4064,50 @@
|
||||
"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": "2ceb16e09034aa4e3213e8fb69dd209b",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "7ecdc512653325abef8e66e9c3e0e479",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "70a1c3300cb0610a85449d08b3483a54",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "000738cc726938ff5282d211629739e3",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "e4d0b9fdcb16f2bef3891f28b950daac",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "9cc960c0de9e10dd300561dc9ae045e2",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "be453afedfb331abe39e4940755b34e7",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "d478af40d922a68e4deab6dd452b0e51",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "5fdb7d8752f9a8315a5f94a32b5db368",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "433dae3372f05c7faf75658c6f962be1",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "d66d0201decc90f677520f41ac227a71",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "37efebdbd1866b71ac324f5ca949151a",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "5ccfadd91168c07956328dd11b118b28",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "404d9db4de7089346264f3f62dbb6d88",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "ef3dda575b711a0fa515f93ebd0a7379",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8ee2be9a35e12158c0ace56b04a3ea99",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "1c305bde639f5fc76e908a3a3fb9203f",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "e58ce9a499068e682295dd3d88a0801d",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "38a2c503c8d892d7e94cd53fb4da5b48",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "deea2cf3afb5598ed9eb6ce4798b1cef",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "a3607fd941915ab11503f82acfc392b5",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "b5a129d83796c9e7015ab5e319d2c22f",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "a3607fd941915ab11503f82acfc392b5",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "b5a129d83796c9e7015ab5e319d2c22f",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "13405a4a16a71d073b6b3cabbbcd9666",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "86b26dc84cc7fa7095e51cfcae759c0b",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "13405a4a16a71d073b6b3cabbbcd9666",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "86b26dc84cc7fa7095e51cfcae759c0b",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "678e09ecd5da367ce290ca7318617b61",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "a9cdc9dd029dabc6dfa5b61d33de7927",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "678e09ecd5da367ce290ca7318617b61",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "a9cdc9dd029dabc6dfa5b61d33de7927",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "4811585805942428ddb217917e4ad843",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "c5c40967e63471c9c4abd6dfbef892df",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "d34c0a142e7d391a109a33ea3cc77c08",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "c5c40967e63471c9c4abd6dfbef892df",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "9d23a52a0c270710332bf35297db9f36",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "61d84134e4088e5138ceb200ba20960b",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "a7a9854fb6f114ac3f3f35c451170328",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "f5a2d196943141917b1ee0f3beb1f5eb",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "ec0052c95df6ea5cb3bdcaabcb1ea55c",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "d21984e95164c4e7df91b35a60828fc7",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "b613c7699c66c9a2a17bf9360015ade0",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "6f907f7940d2f5e44874e24f9a1856a0",
|
||||
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "c0e542e25f839b32d91a07046bd56333",
|
||||
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "f159a31dcd46f144cc796a6f2cbb0a2a",
|
||||
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "f0a7e6c9ad568b229b8299ac15a485b4",
|
||||
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "4c453da417e3e2ab696009f3efb0cbc5",
|
||||
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "56b10a97ac10e4ff9ae854616f3d58de",
|
||||
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "e6a5ecde216f1c180321eec53de8e54d",
|
||||
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "3170eb1b194b77204b5b3454d271e10d",
|
||||
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "368f1eb9a45f3e0d7452e5770f67bd65",
|
||||
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "4376bee2a3d9b1ac98f418e981bd6b5e",
|
||||
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "241bcdfb4a528a4f9714efa9c086a6a6",
|
||||
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "ed0ae25a5332c9e90bc576a41b0e6397",
|
||||
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "b0fc89d99bfacf8326a313c0c9d89065",
|
||||
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "ab540c6524dfdc31ef55be4726f6a978",
|
||||
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "d0e6d409f0f5bfa339060bd6024b10f7",
|
||||
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "287d4e643461591bb897d26f9b24a600",
|
||||
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "8f53ad04b1de065d104b7fd28da0e79c",
|
||||
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "74fa35f559c38176ff91c794b78d06e2",
|
||||
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "2cb71ce71f4ac5d8d2bda2af1ebc87b5",
|
||||
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "53ac1a5d801ae8ae82de21ec9d9a6b8d",
|
||||
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "113c82cf8b6c95a2c940c45b97e4b894",
|
||||
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "6ccd6f2bd0e20520063d4bf8e2c016d0",
|
||||
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "82e76d58eab4962ee7567fbc655072d6",
|
||||
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "6ccd6f2bd0e20520063d4bf8e2c016d0",
|
||||
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "82e76d58eab4962ee7567fbc655072d6",
|
||||
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "e2ca657abc7945934c4b33602ecfbace",
|
||||
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "5b24b2e91fb5c6eca673b0c35bbaf4ca",
|
||||
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "e2ca657abc7945934c4b33602ecfbace",
|
||||
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "5b24b2e91fb5c6eca673b0c35bbaf4ca",
|
||||
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "cfa1c3ca813c3974316cc0abbb56277b",
|
||||
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "73a49adbf5e205d927eda1a2272a3e98",
|
||||
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "cfa1c3ca813c3974316cc0abbb56277b",
|
||||
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "73a49adbf5e205d927eda1a2272a3e98",
|
||||
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "a882153cd74bdb5c1b84d2c46a290527",
|
||||
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "6b00cce1baf5f95d36ae911cdcb23dba",
|
||||
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "8708149fb6208e4e5889b4742784623d",
|
||||
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "6b00cce1baf5f95d36ae911cdcb23dba",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "dc9d6facd1062a48245d5fcb603fe5d6",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "987b189ddac1f90808357749dd44fb2c",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "bf8be09124840f7af212918fa98a34ec",
|
||||
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "33ad88b1557e2828c8e0d8be10d9a5ca",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "3cec3a2d11567ff3dda36ace808c6082",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "b69a204fea2b6fcfee2cbce63a8edd9a",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "59874804f88d67858d988cbc746ca601",
|
||||
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "d9cb15a56ce8f6e3870cb2a5c83defda",
|
||||
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
|
||||
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
|
||||
"src/ballistica/base/mgen/pyembed/binding_base.inc": "ad347097a38e0d7ede9eb6dec6a80ee9",
|
||||
|
||||
1
.idea/dictionaries/ericf.xml
generated
1
.idea/dictionaries/ericf.xml
generated
@ -2318,6 +2318,7 @@
|
||||
<w>projpath</w>
|
||||
<w>projprefix</w>
|
||||
<w>projroot</w>
|
||||
<w>projrootstr</w>
|
||||
<w>projs</w>
|
||||
<w>projsrc</w>
|
||||
<w>projtxt</w>
|
||||
|
||||
12
CHANGELOG.md
12
CHANGELOG.md
@ -1,5 +1,11 @@
|
||||
### 1.7.28 (build 21306, api 8, 2023-09-06)
|
||||
### 1.7.28 (build 21322, api 8, 2023-09-07)
|
||||
|
||||
- Renamed Console to DevConsole, and added an option under advanced settings to
|
||||
always show an ugly 'dev' button onscreen which can be used to toggle it. The
|
||||
backtick key still works also for anyone with a keyboard. I plan to add more
|
||||
functionality besides just the Python console to the dev-console, and perhaps
|
||||
improve the Python console a bit too (add support for on-screen keyboards,
|
||||
etc.)
|
||||
- Added some high level functionality for copying and deleting feature-sets to
|
||||
the `spinoff` tool. For example, to create your own `poo` feature-set based on
|
||||
the existing `template_fs` one, do `tools/spinoff fset-copy template_fs poo`.
|
||||
@ -16,6 +22,10 @@
|
||||
significantly faster & more efficient.
|
||||
- Updated internal Python builds for Apple & iOS to 3.11.5, and updated a few
|
||||
dependent libraries as well (OpenSSL bumped from 3.0.8 to 3.0.10, etc.).
|
||||
- Cleaned up the `babase.quit()` mechanism a bit. The default for the 'soft' arg
|
||||
is now true, so a raw `babase.quit()` should now be a good citizen on mobile
|
||||
platforms. Also added the `g_base->QuitApp()` call which gives the C++ layer
|
||||
an equivalent to the Python call.
|
||||
|
||||
### 1.7.27 (build 21282, api 8, 2023-08-30)
|
||||
|
||||
|
||||
1
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
1
ballisticakit-cmake/.idea/dictionaries/ericf.xml
generated
@ -1378,6 +1378,7 @@
|
||||
<w>projname</w>
|
||||
<w>projpath</w>
|
||||
<w>projprefix</w>
|
||||
<w>projrootstr</w>
|
||||
<w>projsrc</w>
|
||||
<w>projtxt</w>
|
||||
<w>prolly</w>
|
||||
|
||||
@ -424,8 +424,8 @@ set(BALLISTICA_SOURCES
|
||||
${BA_SRC_ROOT}/ballistica/base/support/stress_test.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/support/stress_test.h
|
||||
${BA_SRC_ROOT}/ballistica/base/support/ui_v1_soft.h
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/console.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/console.h
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/dev_console.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/dev_console.h
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/ui.cc
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/ui.h
|
||||
${BA_SRC_ROOT}/ballistica/base/ui/widget_message.h
|
||||
|
||||
@ -410,8 +410,8 @@
|
||||
<ClCompile Include="..\..\src\ballistica\base\support\stress_test.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\console.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\console.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h" />
|
||||
|
||||
@ -664,10 +664,10 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h">
|
||||
<Filter>ballistica\base\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\console.cc">
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc">
|
||||
<Filter>ballistica\base\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\console.h">
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h">
|
||||
<Filter>ballistica\base\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc">
|
||||
|
||||
@ -405,8 +405,8 @@
|
||||
<ClCompile Include="..\..\src\ballistica\base\support\stress_test.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\support\stress_test.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\console.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\console.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h" />
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\ui.h" />
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\widget_message.h" />
|
||||
|
||||
@ -664,10 +664,10 @@
|
||||
<ClInclude Include="..\..\src\ballistica\base\support\ui_v1_soft.h">
|
||||
<Filter>ballistica\base\support</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\console.cc">
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\dev_console.cc">
|
||||
<Filter>ballistica\base\ui</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\console.h">
|
||||
<ClInclude Include="..\..\src\ballistica\base\ui\dev_console.h">
|
||||
<Filter>ballistica\base\ui</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\..\src\ballistica\base\ui\ui.cc">
|
||||
|
||||
@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = {'core'}
|
||||
|
||||
@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = {
|
||||
@ -27,7 +27,7 @@ fset.soft_requirements = {'plus'}
|
||||
# We provide 'babase.app.classic'.
|
||||
fset.has_python_app_subsystem = True
|
||||
|
||||
# If 'plus' is present, our subsystem should be inited after it
|
||||
# If 'plus' is present, our subsystem should be inited *after* it
|
||||
# (classic accounts key off of plus's v2 accounts)
|
||||
fset.python_app_subsystem_dependencies = {'plus'}
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = set()
|
||||
|
||||
@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = {'core', 'base'}
|
||||
|
||||
@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = {'core', 'base', 'classic', 'scene_v1_lib'}
|
||||
|
||||
@ -9,9 +9,10 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
# We're just a library of Python stuff; no C++ here.
|
||||
fset.has_python_binary_module = False
|
||||
|
||||
fset.requirements = {'core', 'base', 'scene_v1'}
|
||||
|
||||
@ -9,7 +9,7 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = {'core', 'base'}
|
||||
|
||||
@ -10,7 +10,7 @@ from __future__ import annotations
|
||||
from batools.featureset import FeatureSet
|
||||
from batools.dummymodule import DummyModuleDef
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
fset.requirements = {'core', 'base'}
|
||||
|
||||
@ -9,9 +9,10 @@ from __future__ import annotations
|
||||
|
||||
from batools.featureset import FeatureSet
|
||||
|
||||
# Grab the FeatureSet we should apply to.
|
||||
# Grab the FeatureSet we're defining here.
|
||||
fset = FeatureSet.get_active()
|
||||
|
||||
# We're just a library of Python stuff; no C++.
|
||||
fset.has_python_binary_module = False
|
||||
|
||||
fset.requirements = {'core', 'base', 'ui_v1', 'classic'}
|
||||
|
||||
@ -3,31 +3,30 @@
|
||||
# pylint: disable=missing-module-docstring, invalid-name
|
||||
from __future__ import annotations
|
||||
|
||||
# This file is exec'ed by tools/spinoff, allowing us to customize
|
||||
# how this src project gits filtered into dst projects.
|
||||
# This file is exec'ed by tools/spinoff, allowing us to customize how
|
||||
# this src project gits filtered into dst projects.
|
||||
|
||||
from batools.spinoff import SpinoffContext
|
||||
|
||||
# Grab the context we should apply to.
|
||||
ctx = SpinoffContext.get_active()
|
||||
|
||||
# As a src project, we set up a baseline set of rules based on what
|
||||
# we contain. The dst project config (exec'ed after us) is then free
|
||||
# to override based on what they want of ours or what they add
|
||||
# themselves.
|
||||
# As a src project, we set up a baseline set of rules based on what we
|
||||
# contain. The dst project config (exec'ed after us) is then free to
|
||||
# override based on what they want of ours or what they add themselves.
|
||||
|
||||
# Any files/dirs with these base names will be ignored by spinoff
|
||||
# on both src and dst.
|
||||
# Any files/dirs with these base names will be ignored by spinoff on
|
||||
# both src and dst.
|
||||
ctx.ignore_names = {
|
||||
'__pycache__',
|
||||
'.git',
|
||||
'.mypy_cache',
|
||||
}
|
||||
|
||||
# Special set of paths managed by spinoff but ALSO stored in git in
|
||||
# the dst project. This is for bare minimum stuff needed to be always
|
||||
# present in dst for bootstrapping, indexing by github, etc). Changes
|
||||
# to these files in dst will be silently and happily overwritten by
|
||||
# Special set of paths managed by spinoff but ALSO stored in git in the
|
||||
# dst project. This is for bare minimum stuff needed to be always
|
||||
# present in dst for bootstrapping, indexing by github, etc). Changes to
|
||||
# these files in dst will be silently and happily overwritten by
|
||||
# spinoff, so tread carefully.
|
||||
ctx.git_mirrored_paths = {
|
||||
'.gitignore',
|
||||
@ -36,16 +35,16 @@ ctx.git_mirrored_paths = {
|
||||
'config/jenkins',
|
||||
}
|
||||
|
||||
# File names that can be quietly ignored or cleared out when found.
|
||||
# This should encompass things like .DS_Store files created by the
|
||||
# Mac Finder when browsing directories. This helps spinoff remove
|
||||
# empty directories when doing a 'clean', etc.
|
||||
# File names that can be quietly ignored or cleared out when found. This
|
||||
# should encompass things like .DS_Store files created by the Mac Finder
|
||||
# when browsing directories. This helps spinoff remove empty directories
|
||||
# when doing a 'clean', etc.
|
||||
ctx.cruft_file_names = {'.DS_Store'}
|
||||
|
||||
# These paths in the src project will be skipped over during updates and
|
||||
# not synced into the dst project. The dst project can use this to
|
||||
# trim out parts of the src project that it doesn't want or that it
|
||||
# intends to 'override' with its own versions.
|
||||
# not synced into the dst project. The dst project can use this to trim
|
||||
# out parts of the src project that it doesn't want or that it intends
|
||||
# to 'override' with its own versions.
|
||||
ctx.src_omit_paths = {
|
||||
'.gitignore',
|
||||
'config/spinoffconfig.py',
|
||||
@ -63,27 +62,27 @@ ctx.src_omit_paths = {
|
||||
# within it from being synced by spinoff; it just means that each of
|
||||
# those individual spinoff-managed files will have their own gitignore
|
||||
# entry since there is no longer one covering the whole dir. So to keep
|
||||
# things tidy, carve out the minimal set of exact file/dir paths that you
|
||||
# need.
|
||||
# things tidy, carve out the minimal set of exact file/dir paths that
|
||||
# you need.
|
||||
ctx.src_write_paths = {
|
||||
'tools/spinoff',
|
||||
'config/spinoffconfig.py',
|
||||
}
|
||||
|
||||
# Normally spinoff errors if it finds any files in its managed dirs
|
||||
# that it did not put there. This is to prevent accidentally working
|
||||
# in these parts of a dst project; since these sections are git-ignored,
|
||||
# git itself won't raise any warnings in such cases and it would be easy
|
||||
# to accidentally lose work otherwise.
|
||||
# Normally spinoff errors if it finds any files in its managed dirs that
|
||||
# it did not put there. This is to prevent accidentally working in these
|
||||
# parts of a dst project; since these sections are git-ignored, git
|
||||
# itself won't raise any warnings in such cases and it would be easy to
|
||||
# accidentally lose work otherwise.
|
||||
#
|
||||
# This list can be used to suppress spinoff's errors for specific
|
||||
# locations. This is generally used to allow build output or other
|
||||
# dynamically generated files to exist within spinoff-managed
|
||||
# directories. It is possible to use src_write_paths for such purposes,
|
||||
# but this has the side-effect of greatly complicating the dst
|
||||
# project's gitignore list; selectively marking a few dirs as
|
||||
# unchecked makes for a cleaner setup. Just be careful to not set
|
||||
# excessively broad regions as unchecked; you don't want to mask
|
||||
# actual useful error messages.
|
||||
# but this has the side-effect of greatly complicating the dst project's
|
||||
# gitignore list; selectively marking a few dirs as unchecked makes for
|
||||
# a cleaner setup. Just be careful to not set excessively broad regions
|
||||
# as unchecked; you don't want to mask actual useful error messages.
|
||||
ctx.src_unchecked_paths = {
|
||||
'src/ballistica/mgen',
|
||||
'src/ballistica/*/mgen',
|
||||
@ -102,12 +101,12 @@ ctx.src_unchecked_paths = {
|
||||
'ballisticakit-android/BallisticaKit/.cxx',
|
||||
}
|
||||
|
||||
# Paths/names/suffixes we consider 'project' files.
|
||||
# These files are synced after all other files and go through
|
||||
# batools.project.Updater class as part of their filtering.
|
||||
# This allows them to update themselves in the same way as they
|
||||
# do when running 'make update' for the project; adding the final
|
||||
# filtered set of project source files to themself, etc.
|
||||
# Paths/names/suffixes we consider 'project' files. These files are
|
||||
# synced after all other files and go through batools.project.Updater
|
||||
# class as part of their filtering. This allows them to update
|
||||
# themselves in the same way as they do when running 'make update' for
|
||||
# the project; adding the final filtered set of project source files to
|
||||
# themself, etc.
|
||||
ctx.project_file_paths = {'src/assets/ba_data/python/babase/_app.py'}
|
||||
ctx.project_file_names = {
|
||||
'Makefile',
|
||||
@ -124,15 +123,16 @@ ctx.project_file_suffixes = {
|
||||
'.pbxproj',
|
||||
}
|
||||
|
||||
# Everything actually synced into dst will use the following filter rules:
|
||||
# Everything actually synced into dst will use the following filter
|
||||
# rules:
|
||||
|
||||
# If files are 'filtered' it means they will have all instances
|
||||
# of BallisticaKit in their names and contents replaced with their
|
||||
# project name. Other custom filtering can also be applied. Obviously
|
||||
# filtering should not be run on certain files (binary data, etc.)
|
||||
# and disabling it where not needed can improve efficiency and make
|
||||
# backporting easier (editing spinoff-managed files in dst and getting
|
||||
# those changes back into src).
|
||||
# If files are 'filtered' it means they will have all instances of
|
||||
# BallisticaKit in their names and contents replaced with their project
|
||||
# name. Other custom filtering can also be applied. Obviously filtering
|
||||
# should not be run on certain files (binary data, etc.) and disabling
|
||||
# it where not needed can improve efficiency and make backporting easier
|
||||
# (editing spinoff-managed files in dst and getting those changes back
|
||||
# into src).
|
||||
|
||||
# Anything under these dirs WILL be filtered.
|
||||
ctx.filter_dirs = {
|
||||
@ -153,8 +153,8 @@ ctx.no_filter_dirs = {
|
||||
'src/assets/windows',
|
||||
}
|
||||
|
||||
# ELSE files matching these exact base names WILL be filtered
|
||||
# (so FOO matches a/b/FOO as well as just FOO).
|
||||
# ELSE files matching these exact base names WILL be filtered (so FOO
|
||||
# matches a/b/FOO as well as just FOO).
|
||||
ctx.filter_file_names = {
|
||||
'Makefile',
|
||||
'.gitignore',
|
||||
|
||||
@ -118,15 +118,16 @@ class App:
|
||||
# This section generated by batools.appmodule; do not edit.
|
||||
|
||||
# Ask our default app modes to handle it.
|
||||
# (based on 'default_app_modes' in projectconfig).
|
||||
# (generated from 'default_app_modes' in projectconfig).
|
||||
import bascenev1
|
||||
import babase
|
||||
|
||||
if bascenev1.SceneV1AppMode.can_handle_intent(intent):
|
||||
return bascenev1.SceneV1AppMode
|
||||
|
||||
if babase.EmptyAppMode.can_handle_intent(intent):
|
||||
return babase.EmptyAppMode
|
||||
for appmode in [
|
||||
bascenev1.SceneV1AppMode,
|
||||
babase.EmptyAppMode,
|
||||
]:
|
||||
if appmode.can_handle_intent(intent):
|
||||
return appmode
|
||||
|
||||
return None
|
||||
|
||||
@ -1057,6 +1058,7 @@ class App:
|
||||
@property
|
||||
def protocol_version(self) -> int:
|
||||
"""(internal)."""
|
||||
# pylint: disable=cyclic-import
|
||||
import bascenev1
|
||||
|
||||
warnings.warn(
|
||||
|
||||
@ -52,7 +52,7 @@ if TYPE_CHECKING:
|
||||
|
||||
# Build number and version of the ballistica binary we expect to be
|
||||
# using.
|
||||
TARGET_BALLISTICA_BUILD = 21306
|
||||
TARGET_BALLISTICA_BUILD = 21322
|
||||
TARGET_BALLISTICA_VERSION = '1.7.28'
|
||||
|
||||
|
||||
|
||||
@ -350,7 +350,7 @@ class CoopBrowserWindow(bui.Window):
|
||||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.purchase as _unused1
|
||||
import bauiv1lib.coop.gamebutton as _unused2
|
||||
import bauiv1lib.confirm as _unused3
|
||||
|
||||
@ -92,7 +92,7 @@ class MainMenuWindow(bui.Window):
|
||||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.getremote as _unused
|
||||
import bauiv1lib.confirm as _unused2
|
||||
import bauiv1lib.store.button as _unused3
|
||||
|
||||
@ -513,7 +513,7 @@ class PlayWindow(bui.Window):
|
||||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.mainmenu as _unused1
|
||||
import bauiv1lib.account as _unused2
|
||||
import bauiv1lib.coop.browser as _unused3
|
||||
|
||||
@ -16,7 +16,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
class AdvancedSettingsWindow(bui.Window):
|
||||
"""Window for editing advanced game settings."""
|
||||
"""Window for editing advanced app settings."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
@ -61,6 +61,7 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._spacing = 32
|
||||
self._menu_open = False
|
||||
top_extra = 10 if uiscale is bui.UIScale.SMALL else 0
|
||||
|
||||
super().__init__(
|
||||
root_widget=bui.containerwidget(
|
||||
size=(self._width, self._height + top_extra),
|
||||
@ -93,7 +94,7 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
self._scroll_width = self._width - (100 + 2 * x_inset)
|
||||
self._scroll_height = self._height - 115.0
|
||||
self._sub_width = self._scroll_width * 0.95
|
||||
self._sub_height = 724.0
|
||||
self._sub_height = 766.0
|
||||
|
||||
if self._show_always_use_internal_keyboard:
|
||||
self._sub_height += 62
|
||||
@ -185,7 +186,7 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
from babase import modutils as _unused2
|
||||
from bauiv1lib import config as _unused1
|
||||
from bauiv1lib.settings import vrtesting as _unused3
|
||||
@ -474,6 +475,19 @@ class AdvancedSettingsWindow(bui.Window):
|
||||
maxwidth=430,
|
||||
)
|
||||
|
||||
v -= 42
|
||||
self._show_dev_console_button_check_box = ConfigCheckBox(
|
||||
parent=self._subcontainer,
|
||||
position=(50, v),
|
||||
size=(self._sub_width - 100, 30),
|
||||
configkey='Show Dev Console Button',
|
||||
displayname=bui.Lstr(
|
||||
resource=f'{self._r}.showDevConsoleButtonText'
|
||||
),
|
||||
scale=1.0,
|
||||
maxwidth=430,
|
||||
)
|
||||
|
||||
v -= 42
|
||||
self._disable_camera_shake_check_box = ConfigCheckBox(
|
||||
parent=self._subcontainer,
|
||||
|
||||
@ -224,7 +224,7 @@ class AllSettingsWindow(bui.Window):
|
||||
# noinspection PyUnresolvedReferences
|
||||
@staticmethod
|
||||
def _preload_modules() -> None:
|
||||
"""Preload modules we use (called in bg thread)."""
|
||||
"""Preload modules we use; avoids hitches (called in bg thread)."""
|
||||
import bauiv1lib.mainmenu as _unused1
|
||||
import bauiv1lib.settings.controls as _unused2
|
||||
import bauiv1lib.settings.graphics as _unused3
|
||||
|
||||
@ -66,6 +66,6 @@ void AppMode::LanguageChanged() {}
|
||||
|
||||
auto AppMode::LastClientJoinTime() const -> millisecs_t { return -1; }
|
||||
|
||||
auto AppMode::InMainMenu() const -> bool { return false; }
|
||||
auto AppMode::InClassicMainMenuSession() const -> bool { return false; }
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -79,8 +79,8 @@ class AppMode {
|
||||
/// Called when language changes.
|
||||
virtual void LanguageChanged();
|
||||
|
||||
/// Are we currently in a 'main menu'?
|
||||
virtual auto InMainMenu() const -> bool;
|
||||
/// Are we currently in a classic 'main menu' session?
|
||||
virtual auto InClassicMainMenuSession() const -> bool;
|
||||
|
||||
/// Get current party size (for legacy parties).
|
||||
virtual auto GetPartySize() const -> int;
|
||||
|
||||
@ -50,8 +50,10 @@ void AppModeEmpty::DrawWorld(base::FrameDef* frame_def) {
|
||||
sinf(static_cast<float>(frame_def->display_time_millisecs()) / 600.0f);
|
||||
auto yoffs =
|
||||
cosf(static_cast<float>(frame_def->display_time_millisecs()) / 600.0f);
|
||||
|
||||
// Z value -1 will draw us under most everything.
|
||||
c.Translate(pass->virtual_width() * 0.5f - 70.0f + xoffs * 200.0f,
|
||||
pass->virtual_height() * 0.5f - 20.0f + yoffs * 200.0f);
|
||||
pass->virtual_height() * 0.5f - 20.0f + yoffs * 200.0f, -1.0f);
|
||||
c.Scale(2.0, 2.0);
|
||||
|
||||
int text_elem_count = grp.GetElementCount();
|
||||
|
||||
@ -24,7 +24,7 @@
|
||||
#include "ballistica/base/support/plus_soft.h"
|
||||
#include "ballistica/base/support/stdio_console.h"
|
||||
#include "ballistica/base/support/stress_test.h"
|
||||
#include "ballistica/base/ui/console.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
#include "ballistica/core/python/core_python.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
@ -156,7 +156,7 @@ void BaseFeatureSet::OnAssetsAvailable() {
|
||||
|
||||
// Spin up the in-app console.
|
||||
if (!g_core->HeadlessMode()) {
|
||||
console_ = new Console();
|
||||
console_ = new DevConsole();
|
||||
|
||||
// Print any messages that have built up.
|
||||
if (!console_startup_messages_.empty()) {
|
||||
@ -234,7 +234,7 @@ void BaseFeatureSet::OnAppShutdownComplete() {
|
||||
if (app_adapter->ManagesEventLoop()) {
|
||||
g_core->main_event_loop()->Quit();
|
||||
} else {
|
||||
platform->QuitApp();
|
||||
platform->TerminateApp();
|
||||
}
|
||||
}
|
||||
|
||||
@ -747,4 +747,18 @@ void BaseFeatureSet::ShutdownSuppressDisallow() {
|
||||
|
||||
auto BaseFeatureSet::GetReturnValue() const -> int { return return_value(); }
|
||||
|
||||
void BaseFeatureSet::QuitApp(QuitType quit_type) {
|
||||
// If they ask for 'back' and we support that, do it.
|
||||
// Otherwise if they want 'back' or 'soft' and we support soft, do it.
|
||||
// Otherwise go with a regular app shutdown.
|
||||
if (quit_type == QuitType::kBack && g_base->platform->CanBackQuit()) {
|
||||
logic->event_loop()->PushCall([this] { platform->DoBackQuit(); });
|
||||
} else if ((quit_type == QuitType::kBack || quit_type == QuitType::kSoft)
|
||||
&& g_base->platform->CanSoftQuit()) {
|
||||
logic->event_loop()->PushCall([this] { platform->DoSoftQuit(); });
|
||||
} else {
|
||||
logic->event_loop()->PushCall([this] { logic->Shutdown(); });
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -53,7 +53,7 @@ class Camera;
|
||||
class ClassicSoftInterface;
|
||||
class CollisionMeshAsset;
|
||||
class CollisionCache;
|
||||
class Console;
|
||||
class DevConsole;
|
||||
class Context;
|
||||
class ContextRef;
|
||||
class DataAsset;
|
||||
@ -121,6 +121,18 @@ class UIV1SoftInterface;
|
||||
class AppAdapterVR;
|
||||
class GraphicsVR;
|
||||
|
||||
enum class QuitType {
|
||||
/// Leads to the process exiting.
|
||||
kHard,
|
||||
/// May hide/reset the app but keep the process running. Generally how
|
||||
/// mobile apps behave.
|
||||
kSoft,
|
||||
/// Same as kSoft but gives 'back-button-pressed' behavior which may
|
||||
/// differ depending on the OS (returning to a previous Activity in
|
||||
/// Android instead of dumping to the home screen, etc.)
|
||||
kBack,
|
||||
};
|
||||
|
||||
enum class AssetType {
|
||||
kTexture,
|
||||
kCollisionMesh,
|
||||
@ -601,6 +613,14 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
||||
/// Start app systems in motion.
|
||||
void StartApp() override;
|
||||
|
||||
/// Issue a high level app quit request. Can be called from any thread.
|
||||
/// 'soft' means the app can simply reset/hide itself instead of actually
|
||||
/// exiting the process (common behavior on mobile platforms). 'back'
|
||||
/// means that a soft-quit should behave as if a back-button was pressed,
|
||||
/// whic may trigger different behavior in the OS than a standard soft
|
||||
/// quit.
|
||||
void QuitApp(QuitType quit_type = QuitType::kSoft);
|
||||
|
||||
/// Called when app shutdown process completes. Sets app to exit.
|
||||
void OnAppShutdownComplete();
|
||||
|
||||
@ -759,7 +779,7 @@ class BaseFeatureSet : public FeatureSetNativeComponent,
|
||||
void PrintContextUnavailable_();
|
||||
|
||||
AppMode* app_mode_;
|
||||
Console* console_{};
|
||||
DevConsole* console_{};
|
||||
PlusSoftInterface* plus_soft_{};
|
||||
ClassicSoftInterface* classic_soft_{};
|
||||
UIV1SoftInterface* ui_v1_soft_{};
|
||||
|
||||
@ -11,6 +11,17 @@ namespace ballistica::base {
|
||||
|
||||
class RenderComponent {
|
||||
public:
|
||||
class ScopedTransformObj {
|
||||
public:
|
||||
explicit ScopedTransformObj(RenderComponent* c) : c_{c} {
|
||||
c_->PushTransform();
|
||||
}
|
||||
~ScopedTransformObj() { c_->PopTransform(); }
|
||||
|
||||
private:
|
||||
RenderComponent* c_;
|
||||
};
|
||||
|
||||
explicit RenderComponent(RenderPass* pass)
|
||||
: state_(State::kConfiguring), pass_(pass), cmd_buffer_(nullptr) {}
|
||||
~RenderComponent() {
|
||||
@ -82,6 +93,9 @@ class RenderComponent {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kPopTransform);
|
||||
}
|
||||
auto ScopedTransform() -> ScopedTransformObj {
|
||||
return ScopedTransformObj(this);
|
||||
}
|
||||
void Translate(float x, float y) {
|
||||
EnsureDrawing();
|
||||
cmd_buffer_->PutCommand(RenderCommandBuffer::Command::kTranslate2);
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/base/python/support/python_context_call.h"
|
||||
#include "ballistica/base/support/app_config.h"
|
||||
#include "ballistica/base/ui/console.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
#include "ballistica/core/core.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
@ -34,7 +34,6 @@ const float kScreenMeshZDepth{-0.05f};
|
||||
const float kProgressBarZDepth{0.0f};
|
||||
const int kProgressBarFadeTime{500};
|
||||
const float kDebugImgZDepth{-0.04f};
|
||||
const float kCursorZDepth{-0.1f};
|
||||
|
||||
auto Graphics::IsShaderTransparent(ShadingType c) -> bool {
|
||||
switch (c) {
|
||||
@ -105,8 +104,8 @@ void Graphics::OnAppShutdown() { assert(g_base->InLogicThread()); }
|
||||
void Graphics::DoApplyAppConfig() {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Not relevant for fullscreen anymore
|
||||
// since we're fullscreen windows everywhere.
|
||||
// Not relevant for fullscreen anymore since we use fullscreen windows.
|
||||
// everywhere.
|
||||
int width = 800;
|
||||
int height = 600;
|
||||
|
||||
@ -158,28 +157,20 @@ void Graphics::DoApplyAppConfig() {
|
||||
|
||||
// Note: when the graphics-thread applies the first set-screen event it will
|
||||
// trigger the remainder of startup such as media-loading; make sure nothing
|
||||
// below this will affect that.
|
||||
// below this point will affect that.
|
||||
g_base->graphics_server->PushSetScreenCall(
|
||||
fullscreen, width, height, texture_quality_requested,
|
||||
graphics_quality_requested, android_res);
|
||||
|
||||
set_show_fps(g_base->app_config->Resolve(AppConfig::BoolID::kShowFPS));
|
||||
set_show_ping(g_base->app_config->Resolve(AppConfig::BoolID::kShowPing));
|
||||
show_fps_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowFPS);
|
||||
show_ping_ = g_base->app_config->Resolve(AppConfig::BoolID::kShowPing);
|
||||
tv_border_ = g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
||||
|
||||
g_base->graphics_server->PushSetScreenGammaCall(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenGamma));
|
||||
g_base->graphics_server->PushSetScreenPixelScaleCall(
|
||||
g_base->app_config->Resolve(AppConfig::FloatID::kScreenPixelScale));
|
||||
|
||||
// Set tv border (for both client and server).
|
||||
// FIXME: this should exist either on the client or the server; not both.
|
||||
// (and should be communicated via frameldefs/etc.)
|
||||
bool tv_border =
|
||||
g_base->app_config->Resolve(AppConfig::BoolID::kEnableTVBorder);
|
||||
g_base->graphics_server->event_loop()->PushCall(
|
||||
[tv_border] { g_base->graphics_server->set_tv_border(tv_border); });
|
||||
set_tv_border(tv_border);
|
||||
|
||||
// V-sync setting.
|
||||
std::string v_sync =
|
||||
g_base->app_config->Resolve(AppConfig::StringID::kVerticalSync);
|
||||
@ -313,7 +304,7 @@ void Graphics::SetShadowRange(float lower_bottom, float lower_top,
|
||||
}
|
||||
|
||||
auto Graphics::GetShadowDensity(float x, float y, float z) -> float {
|
||||
if (y < shadow_lower_bottom_) { // NOLINT(bugprone-branch-clone)
|
||||
if (y < shadow_lower_bottom_) {
|
||||
return 0.0f;
|
||||
} else if (y < shadow_lower_top_) {
|
||||
float amt =
|
||||
@ -1108,9 +1099,16 @@ void Graphics::DrawUI(FrameDef* frame_def) {
|
||||
g_base->ui->Draw(frame_def);
|
||||
}
|
||||
|
||||
void Graphics::DrawDevUI(FrameDef* frame_def) {
|
||||
// Just do generic thing in our default implementation.
|
||||
// Special variants like GraphicsVR may do fancier stuff here.
|
||||
g_base->ui->DrawDev(frame_def);
|
||||
}
|
||||
|
||||
void Graphics::BuildAndPushFrameDef() {
|
||||
assert(g_base->InLogicThread());
|
||||
assert(camera_.Exists());
|
||||
assert(!g_core->HeadlessMode());
|
||||
|
||||
// Keep track of when we're in here; can be useful for making sure stuff
|
||||
// doesn't muck with our lists/etc. while we're using them.
|
||||
@ -1167,16 +1165,14 @@ void Graphics::BuildAndPushFrameDef() {
|
||||
|
||||
DrawUI(frame_def);
|
||||
|
||||
// Let input draw anything it needs to. (touch input graphics, etc)
|
||||
// Let input draw anything it needs to (touch input graphics, etc).
|
||||
g_base->input->Draw(frame_def);
|
||||
|
||||
RenderPass* overlay_pass = frame_def->overlay_pass();
|
||||
DrawMiscOverlays(overlay_pass);
|
||||
|
||||
// Draw console.
|
||||
if (!g_core->HeadlessMode() && g_base->console()) {
|
||||
g_base->console()->Draw(overlay_pass);
|
||||
}
|
||||
// Let UI draw dev console and whatever else.
|
||||
DrawDevUI(frame_def);
|
||||
|
||||
DrawCursor(overlay_pass, app_time_millisecs);
|
||||
|
||||
|
||||
@ -19,30 +19,32 @@
|
||||
namespace ballistica::base {
|
||||
|
||||
// Light/shadow res is divided by this to get pure light res.
|
||||
const int kLightResDiv = 4;
|
||||
const int kLightResDiv{4};
|
||||
|
||||
// How we divide up our z depth spectrum:
|
||||
const float kBackingDepth5 = 1.0f;
|
||||
const float kBackingDepth5{1.0f};
|
||||
|
||||
// Background
|
||||
// blit-shapes (with cam buffer)
|
||||
const float kBackingDepth4 = 0.9f;
|
||||
const float kBackingDepth4{0.9f};
|
||||
|
||||
// World (without cam buffer) or overlay-3d (with cam buffer)
|
||||
const float kBackingDepth3C = 0.65f;
|
||||
const float kBackingDepth3B = 0.4f;
|
||||
const float kBackingDepth3 = 0.15f;
|
||||
const float kBackingDepth3C{0.65f};
|
||||
const float kBackingDepth3B{0.4f};
|
||||
const float kBackingDepth3{0.15f};
|
||||
|
||||
// Overlay-3d (without cam buffer) / overlay(vr)
|
||||
const float kBackingDepth2C = 0.147f;
|
||||
const float kBackingDepth2B = 0.143f;
|
||||
const float kBackingDepth2 = 0.14f;
|
||||
const float kBackingDepth2C{0.147f};
|
||||
const float kBackingDepth2B{0.143f};
|
||||
const float kBackingDepth2{0.14f};
|
||||
|
||||
// Overlay(non-vr) // cover (vr)
|
||||
const float kBackingDepth1B = 0.01f;
|
||||
const float kBackingDepth1 = 0.0f;
|
||||
const float kBackingDepth1B{0.01f};
|
||||
const float kBackingDepth1{0.0f};
|
||||
|
||||
const float kShadowNeutral = 0.5f;
|
||||
const float kShadowNeutral{0.5f};
|
||||
|
||||
const float kCursorZDepth{-0.1f};
|
||||
|
||||
// Client class for graphics operations (used from the logic thread).
|
||||
class Graphics {
|
||||
@ -218,13 +220,7 @@ class Graphics {
|
||||
void SetShadowRange(float lower_bottom, float lower_top, float upper_bottom,
|
||||
float upper_top);
|
||||
void ReleaseFadeEndCommand();
|
||||
void set_show_fps(bool val) { show_fps_ = val; }
|
||||
void set_show_ping(bool val) { show_ping_ = val; }
|
||||
// FIXME - move to graphics_server
|
||||
void set_tv_border(bool val) {
|
||||
assert(g_base->InLogicThread());
|
||||
tv_border_ = val;
|
||||
}
|
||||
|
||||
auto tv_border() const -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
return tv_border_;
|
||||
@ -297,8 +293,13 @@ class Graphics {
|
||||
void set_drawing_transparent_only(bool val) {
|
||||
drawing_transparent_only_ = val;
|
||||
}
|
||||
|
||||
/// Draw regular UI.
|
||||
virtual void DrawUI(FrameDef* frame_def);
|
||||
|
||||
/// Draw dev console or whatever else on top of normal stuff.
|
||||
virtual void DrawDevUI(FrameDef* frame_def);
|
||||
|
||||
auto drawing_opaque_only() const -> bool { return drawing_opaque_only_; }
|
||||
void set_drawing_opaque_only(bool val) { drawing_opaque_only_ = val; }
|
||||
|
||||
|
||||
@ -117,6 +117,11 @@ auto GraphicsServer::GetRenderFrameDef() -> FrameDef* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void GraphicsServer::ApplyFrameDefSettings(FrameDef* frame_def) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
tv_border_ = frame_def->tv_border();
|
||||
}
|
||||
|
||||
// Runs any mesh updates contained in the frame-def.
|
||||
void GraphicsServer::RunFrameDefMeshUpdates(FrameDef* frame_def) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
@ -170,6 +175,9 @@ void GraphicsServer::TryRender() {
|
||||
assert(g_base->InGraphicsThread());
|
||||
|
||||
if (FrameDef* frame_def = GetRenderFrameDef()) {
|
||||
// Apply settings such as tv-mode passed along on the frame-def.
|
||||
ApplyFrameDefSettings(frame_def);
|
||||
|
||||
// Note: we always run mesh updates contained in the framedef
|
||||
// even if we don't actually render it.
|
||||
// (Hmm this seems flaky; will TryRender always get called
|
||||
|
||||
@ -52,6 +52,8 @@ class GraphicsServer {
|
||||
// of using the RenderFrameDef* calls
|
||||
auto GetRenderFrameDef() -> FrameDef*;
|
||||
|
||||
void ApplyFrameDefSettings(FrameDef* frame_def);
|
||||
|
||||
void RunFrameDefMeshUpdates(FrameDef* frame_def);
|
||||
|
||||
// renders shadow passes and other common parts of a frame_def
|
||||
@ -215,10 +217,6 @@ class GraphicsServer {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return res_y_virtual_;
|
||||
}
|
||||
void set_tv_border(bool val) {
|
||||
assert(g_base->InGraphicsThread());
|
||||
tv_border_ = val;
|
||||
}
|
||||
auto tv_border() const {
|
||||
assert(g_base->InGraphicsThread());
|
||||
return tv_border_;
|
||||
@ -302,8 +300,8 @@ class GraphicsServer {
|
||||
EventLoop* event_loop_{};
|
||||
float res_x_{};
|
||||
float res_y_{};
|
||||
float res_x_virtual_{0.0f};
|
||||
float res_y_virtual_{0.0f};
|
||||
float res_x_virtual_{};
|
||||
float res_y_virtual_{};
|
||||
bool tv_border_{};
|
||||
bool renderer_context_lost_{};
|
||||
uint32_t texture_compression_types_{};
|
||||
|
||||
@ -72,6 +72,7 @@ void FrameDef::Reset() {
|
||||
|
||||
assert(g_base->graphics->has_supports_high_quality_graphics_value());
|
||||
orbiting_ = (g_base->graphics->camera()->mode() == CameraMode::kOrbit);
|
||||
tv_border_ = g_base->graphics->tv_border();
|
||||
|
||||
shadow_offset_ = g_base->graphics->shadow_offset();
|
||||
shadow_scale_ = g_base->graphics->shadow_scale();
|
||||
|
||||
@ -154,6 +154,7 @@ class FrameDef {
|
||||
auto media_components() const -> const std::vector<Object::Ref<Asset>>& {
|
||||
return media_components_;
|
||||
}
|
||||
auto tv_border() const { return tv_border_; }
|
||||
|
||||
void set_camera_mode(CameraMode val) { camera_mode_ = val; }
|
||||
void set_rendering(bool val) { rendering_ = val; }
|
||||
@ -205,6 +206,7 @@ class FrameDef {
|
||||
std::unique_ptr<RenderPass> blit_pass_;
|
||||
GraphicsQuality quality_{GraphicsQuality::kLow};
|
||||
bool orbiting_{};
|
||||
bool tv_border_{};
|
||||
millisecs_t app_time_millisecs_{};
|
||||
millisecs_t display_time_millisecs_{};
|
||||
millisecs_t display_time_elapsed_millisecs_{};
|
||||
|
||||
@ -12,7 +12,7 @@
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/base/python/base_python.h"
|
||||
#include "ballistica/base/support/app_config.h"
|
||||
#include "ballistica/base/ui/console.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
#include "ballistica/shared/buildconfig/buildconfig_common.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
@ -23,26 +23,14 @@ namespace ballistica::base {
|
||||
Input::Input() = default;
|
||||
|
||||
template <typename F>
|
||||
void SafePushLogicCall(const char* desc, const F& lambda) {
|
||||
// Note: originally this call was created to silently ignore early events
|
||||
// coming in before app stuff was up and running, but that was a bad idea,
|
||||
// as it caused us to ignore device-create messages sometimes which lead
|
||||
// to other issues later. So now I'm trying to fix those problems at the
|
||||
// source, but am leaving this intact for now as a clean way to catch
|
||||
// anything that needs fixing.
|
||||
if (!g_base) {
|
||||
FatalError(std::string(desc) + " called with null g_base.");
|
||||
return;
|
||||
}
|
||||
if (auto* loop = g_base->logic->event_loop()) {
|
||||
loop->PushCall(lambda);
|
||||
} else {
|
||||
FatalError(std::string(desc) + " called before logic event loop created.");
|
||||
}
|
||||
void PushLogicCall(const F& lambda) {
|
||||
assert(g_base);
|
||||
assert(g_base->logic->event_loop());
|
||||
g_base->logic->event_loop()->PushCall(lambda);
|
||||
}
|
||||
|
||||
void Input::PushCreateKeyboardInputDevices() {
|
||||
SafePushLogicCall(__func__, [this] { CreateKeyboardInputDevices(); });
|
||||
PushLogicCall([this] { CreateKeyboardInputDevices(); });
|
||||
}
|
||||
|
||||
void Input::CreateKeyboardInputDevices() {
|
||||
@ -59,7 +47,7 @@ void Input::CreateKeyboardInputDevices() {
|
||||
}
|
||||
|
||||
void Input::PushDestroyKeyboardInputDevices() {
|
||||
SafePushLogicCall(__func__, [this] { DestroyKeyboardInputDevices(); });
|
||||
PushLogicCall([this] { DestroyKeyboardInputDevices(); });
|
||||
}
|
||||
|
||||
void Input::DestroyKeyboardInputDevices() {
|
||||
@ -171,13 +159,14 @@ void Input::CreateTouchInput() {
|
||||
void Input::AnnounceConnects() {
|
||||
static bool first_print = true;
|
||||
|
||||
// For the first announcement just say "X controllers detected" and don't have
|
||||
// a sound.
|
||||
// For the first announcement just say "X controllers detected" and don't
|
||||
// have a sound.
|
||||
if (first_print && g_core->GetAppTimeMillisecs() < 10000) {
|
||||
first_print = false;
|
||||
|
||||
// Disabling this completely for now; being more lenient with devices
|
||||
// allowed on android means this will often come back with large numbers.
|
||||
// allowed on Android means this will often come back with large
|
||||
// numbers.
|
||||
bool do_print{false};
|
||||
|
||||
// If there's been several connected, just give a number.
|
||||
@ -203,7 +192,7 @@ void Input::AnnounceConnects() {
|
||||
&s, "${COUNT}", std::to_string(newly_connected_controllers_.size()));
|
||||
ScreenMessage(s);
|
||||
} else {
|
||||
// If its just one, name it.
|
||||
// If its just one, give its name.
|
||||
std::string s =
|
||||
g_base->assets->GetResourceString("controllerConnectedText");
|
||||
Utils::StringReplaceOne(&s, "${CONTROLLER}",
|
||||
@ -276,7 +265,7 @@ void Input::ShowStandardInputDeviceDisconnectedMessage(InputDevice* j) {
|
||||
|
||||
void Input::PushAddInputDeviceCall(InputDevice* input_device,
|
||||
bool standard_message) {
|
||||
SafePushLogicCall(__func__, [this, input_device, standard_message] {
|
||||
PushLogicCall([this, input_device, standard_message] {
|
||||
AddInputDevice(input_device, standard_message);
|
||||
});
|
||||
}
|
||||
@ -362,7 +351,7 @@ void Input::AddInputDevice(InputDevice* device, bool standard_message) {
|
||||
|
||||
void Input::PushRemoveInputDeviceCall(InputDevice* input_device,
|
||||
bool standard_message) {
|
||||
SafePushLogicCall(__func__, [this, input_device, standard_message] {
|
||||
PushLogicCall([this, input_device, standard_message] {
|
||||
RemoveInputDevice(input_device, standard_message);
|
||||
});
|
||||
}
|
||||
@ -390,8 +379,6 @@ void Input::RemoveInputDevice(InputDevice* input, bool standard_message) {
|
||||
device->DetachFromPlayer();
|
||||
|
||||
// This should kill the device.
|
||||
// FIXME: since many devices get allocated in the main thread,
|
||||
// should we not kill it there too?...
|
||||
device.Clear();
|
||||
UpdateInputDeviceCounts();
|
||||
return;
|
||||
@ -411,10 +398,10 @@ void Input::UpdateInputDeviceCounts() {
|
||||
int total = 0;
|
||||
int controller_count = 0;
|
||||
for (auto& input_device : input_devices_) {
|
||||
// Ok, we now limit non-keyboard non-touchscreen devices to ones that have
|
||||
// been active recently.. (we're starting to get lots of virtual devices and
|
||||
// other cruft on android; don't wanna show controller UIs just due to
|
||||
// those)
|
||||
// Ok, we now limit non-keyboard non-touchscreen devices to ones that
|
||||
// have been active recently.. (we're starting to get lots of virtual
|
||||
// devices and other cruft on android; don't wanna show controller UIs
|
||||
// just due to those)
|
||||
if (input_device.Exists()
|
||||
&& ((*input_device).IsTouchScreen() || (*input_device).IsKeyboard()
|
||||
|| ((*input_device).last_input_time_millisecs() != 0
|
||||
@ -480,7 +467,6 @@ auto Input::GetLocalActiveInputDeviceCount() -> int {
|
||||
|
||||
auto Input::HaveControllerWithPlayer() -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
// NOLINTNEXTLINE(readability-use-anyofallof)
|
||||
for (auto& input_device : input_devices_) {
|
||||
if (input_device.Exists() && (*input_device).IsController()
|
||||
&& (*input_device).AttachedToPlayer()) {
|
||||
@ -492,7 +478,6 @@ auto Input::HaveControllerWithPlayer() -> bool {
|
||||
|
||||
auto Input::HaveRemoteAppController() -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
// NOLINTNEXTLINE(readability-use-anyofallof)
|
||||
for (auto& input_device : input_devices_) {
|
||||
if (input_device.Exists() && (*input_device).IsRemoteApp()) {
|
||||
return true;
|
||||
@ -546,8 +531,8 @@ auto Input::ShouldCompletelyIgnoreInputDevice(InputDevice* input_device)
|
||||
void Input::UpdateEnabledControllerSubsystems() {
|
||||
assert(g_base);
|
||||
|
||||
// First off, on mac, let's update whether we want to completely ignore either
|
||||
// the classic or the iOS/Mac controller subsystems.
|
||||
// First off, on mac, let's update whether we want to completely ignore
|
||||
// either the classic or the iOS/Mac controller subsystems.
|
||||
if (g_buildconfig.ostype_macos()) {
|
||||
std::string sys = g_base->app_config->Resolve(
|
||||
AppConfig::StringID::kMacControllerSubsystem);
|
||||
@ -581,9 +566,9 @@ void Input::DoApplyAppConfig() {
|
||||
|
||||
UpdateEnabledControllerSubsystems();
|
||||
|
||||
// It's technically possible that updating these controls will add or remove
|
||||
// devices, thus changing the input_devices_ list, so lets work with a copy of
|
||||
// it.
|
||||
// It's technically possible that updating these controls will add or
|
||||
// remove devices, thus changing the input_devices_ list, so lets work
|
||||
// with a copy of it.
|
||||
std::vector<Object::Ref<InputDevice> > input_devices = input_devices_;
|
||||
for (auto& input_device : input_devices) {
|
||||
if (input_device.Exists()) {
|
||||
@ -819,7 +804,7 @@ void Input::ProcessStressTesting(int player_count) {
|
||||
}
|
||||
|
||||
void Input::PushTextInputEvent(const std::string& text) {
|
||||
SafePushLogicCall(__func__, [this, text] {
|
||||
PushLogicCall([this, text] {
|
||||
MarkInputActive();
|
||||
|
||||
// Ignore if input is locked.
|
||||
@ -837,7 +822,7 @@ void Input::PushTextInputEvent(const std::string& text) {
|
||||
|
||||
void Input::PushJoystickEvent(const SDL_Event& event,
|
||||
InputDevice* input_device) {
|
||||
SafePushLogicCall(__func__, [this, event, input_device] {
|
||||
PushLogicCall([this, event, input_device] {
|
||||
HandleJoystickEvent(event, input_device);
|
||||
});
|
||||
}
|
||||
@ -871,11 +856,11 @@ void Input::HandleJoystickEvent(const SDL_Event& event,
|
||||
}
|
||||
|
||||
void Input::PushKeyPressEvent(const SDL_Keysym& keysym) {
|
||||
SafePushLogicCall(__func__, [this, keysym] { HandleKeyPress(&keysym); });
|
||||
PushLogicCall([this, keysym] { HandleKeyPress(&keysym); });
|
||||
}
|
||||
|
||||
void Input::PushKeyReleaseEvent(const SDL_Keysym& keysym) {
|
||||
SafePushLogicCall(__func__, [this, keysym] { HandleKeyRelease(&keysym); });
|
||||
PushLogicCall([this, keysym] { HandleKeyRelease(&keysym); });
|
||||
}
|
||||
|
||||
void Input::CaptureKeyboardInput(HandleKeyPressCall* press_call,
|
||||
@ -947,10 +932,9 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||
case SDLK_KP_ENTER:
|
||||
case SDLK_BACKSPACE: {
|
||||
// FIXME: I don't remember what this was put here for, but now that
|
||||
// we
|
||||
// have hardware keyboards it crashes text fields by sending them a
|
||||
// TEXT_INPUT message with no string.. I made them resistant to
|
||||
// that case but wondering if we can take this out?...
|
||||
// we have hardware keyboards it crashes text fields by sending
|
||||
// them a TEXT_INPUT message with no string.. I made them resistant
|
||||
// to that case but wondering if we can take this out?
|
||||
g_base->ui->SendWidgetMessage(
|
||||
WidgetMessage(WidgetMessage::Type::kTextInput, keysym));
|
||||
break;
|
||||
@ -971,7 +955,7 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Control-Q quits. On mac, the usual cmd-q gets handled by SDL/etc.
|
||||
// Control-Q quits. On Mac, the usual cmd-q gets handled by SDL/etc.
|
||||
// implicitly.
|
||||
if (!repeat_press && keysym->sym == SDLK_q && (keysym->mod & KMOD_CTRL)) {
|
||||
g_base->ui->ConfirmQuit();
|
||||
@ -1027,14 +1011,12 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||
}
|
||||
|
||||
case SDLK_F7:
|
||||
SafePushLogicCall(__func__,
|
||||
[] { g_base->graphics->ToggleManualCamera(); });
|
||||
PushLogicCall([] { g_base->graphics->ToggleManualCamera(); });
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
case SDLK_F8:
|
||||
SafePushLogicCall(
|
||||
__func__, [] { g_base->graphics->ToggleNetworkDebugDisplay(); });
|
||||
PushLogicCall([] { g_base->graphics->ToggleNetworkDebugDisplay(); });
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
@ -1045,8 +1027,7 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||
break;
|
||||
|
||||
case SDLK_F10:
|
||||
SafePushLogicCall(__func__,
|
||||
[] { g_base->graphics->ToggleDebugDraw(); });
|
||||
PushLogicCall([] { g_base->graphics->ToggleDebugDraw(); });
|
||||
handled = true;
|
||||
break;
|
||||
|
||||
@ -1080,51 +1061,40 @@ void Input::HandleKeyPress(const SDL_Keysym* keysym) {
|
||||
}
|
||||
|
||||
void Input::HandleKeyRelease(const SDL_Keysym* keysym) {
|
||||
assert(g_base);
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Note: we want to let these through even if input is locked.
|
||||
// Note: we want to let releases through even if input is locked.
|
||||
|
||||
MarkInputActive();
|
||||
|
||||
// If someone is capturing these events, give them a crack at it.
|
||||
if (keyboard_input_capture_release_) {
|
||||
if (keyboard_input_capture_release_(*keysym)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Regardless of what else we do, keep track of mod key states.
|
||||
// (for things like manual camera moves. For individual key presses
|
||||
// ideally we should use the modifiers bundled with the key presses)
|
||||
UpdateModKeyStates(keysym, false);
|
||||
|
||||
// In some cases we may receive duplicate key-release events
|
||||
// (if a keyboard reset was run it deals out key releases but then the
|
||||
// keyboard driver issues them as well)
|
||||
// In some cases we may receive duplicate key-release events (if a
|
||||
// keyboard reset was run, it deals out key releases, but then the
|
||||
// keyboard driver issues them as well).
|
||||
if (keys_held_.count(keysym->sym) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If someone is capturing these events, give them a crack at it.
|
||||
if (keyboard_input_capture_release_) {
|
||||
(keyboard_input_capture_release_(*keysym));
|
||||
}
|
||||
|
||||
// Keep track of mod key states for things like manual camera moves. For
|
||||
// individual key presses ideally we should instead use modifiers bundled
|
||||
// with the key press events.
|
||||
UpdateModKeyStates(keysym, false);
|
||||
|
||||
keys_held_.erase(keysym->sym);
|
||||
|
||||
if (IsInputLocked()) {
|
||||
return;
|
||||
if (g_base->console() != nullptr) {
|
||||
g_base->console()->HandleKeyRelease(keysym);
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
if (g_base && g_base->console() != nullptr
|
||||
&& g_base->console()->HandleKeyRelease(keysym)) {
|
||||
handled = true;
|
||||
}
|
||||
|
||||
// If we haven't claimed it, pass it along as potential player input.
|
||||
if (!handled) {
|
||||
if (keyboard_input_) {
|
||||
keyboard_input_->HandleKey(keysym, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Input::UpdateModKeyStates(const SDL_Keysym* keysym, bool press) {
|
||||
switch (keysym->sym) {
|
||||
@ -1155,15 +1125,17 @@ void Input::UpdateModKeyStates(const SDL_Keysym* keysym, bool press) {
|
||||
}
|
||||
|
||||
void Input::PushMouseScrollEvent(const Vector2f& amount) {
|
||||
SafePushLogicCall(__func__, [this, amount] { HandleMouseScroll(amount); });
|
||||
PushLogicCall([this, amount] { HandleMouseScroll(amount); });
|
||||
}
|
||||
|
||||
void Input::HandleMouseScroll(const Vector2f& amount) {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// If input is locked, allow it to mark us active but nothing more.
|
||||
MarkInputActive();
|
||||
if (IsInputLocked()) {
|
||||
return;
|
||||
}
|
||||
MarkInputActive();
|
||||
|
||||
if (std::abs(amount.y) > 0.0001f) {
|
||||
g_base->ui->SendWidgetMessage(
|
||||
@ -1187,17 +1159,19 @@ void Input::HandleMouseScroll(const Vector2f& amount) {
|
||||
|
||||
void Input::PushSmoothMouseScrollEvent(const Vector2f& velocity,
|
||||
bool momentum) {
|
||||
SafePushLogicCall(__func__, [this, velocity, momentum] {
|
||||
PushLogicCall([this, velocity, momentum] {
|
||||
HandleSmoothMouseScroll(velocity, momentum);
|
||||
});
|
||||
}
|
||||
|
||||
void Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// If input is locked, allow it to mark us active but nothing more.
|
||||
MarkInputActive();
|
||||
if (IsInputLocked()) {
|
||||
return;
|
||||
}
|
||||
MarkInputActive();
|
||||
|
||||
bool handled = false;
|
||||
handled = g_base->ui->SendWidgetMessage(
|
||||
@ -1219,15 +1193,19 @@ void Input::HandleSmoothMouseScroll(const Vector2f& velocity, bool momentum) {
|
||||
}
|
||||
|
||||
void Input::PushMouseMotionEvent(const Vector2f& position) {
|
||||
SafePushLogicCall(__func__,
|
||||
[this, position] { HandleMouseMotion(position); });
|
||||
PushLogicCall([this, position] { HandleMouseMotion(position); });
|
||||
}
|
||||
|
||||
void Input::HandleMouseMotion(const Vector2f& position) {
|
||||
assert(g_base->graphics);
|
||||
assert(g_base);
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
MarkInputActive();
|
||||
|
||||
if (IsInputLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float old_cursor_pos_x = cursor_pos_x_;
|
||||
float old_cursor_pos_y = cursor_pos_y_;
|
||||
|
||||
@ -1240,8 +1218,6 @@ void Input::HandleMouseMotion(const Vector2f& position) {
|
||||
last_mouse_move_time_ = g_core->GetAppTimeMillisecs();
|
||||
mouse_move_count_++;
|
||||
|
||||
bool handled{};
|
||||
|
||||
// If we have a touch-input in editing mode, pass along events to it.
|
||||
// (it usually handles its own events but here we want it to play nice
|
||||
// with stuff under it by blocking touches, etc)
|
||||
@ -1250,48 +1226,35 @@ void Input::HandleMouseMotion(const Vector2f& position) {
|
||||
cursor_pos_y_);
|
||||
}
|
||||
|
||||
// UI interaction.
|
||||
if (!IsInputLocked()) {
|
||||
handled = g_base->ui->SendWidgetMessage(
|
||||
WidgetMessage(WidgetMessage::Type::kMouseMove, nullptr, cursor_pos_x_,
|
||||
cursor_pos_y_));
|
||||
}
|
||||
// Let any UI stuff handle it.
|
||||
g_base->ui->HandleMouseMotion(cursor_pos_x_, cursor_pos_y_);
|
||||
|
||||
// Manual camera motion.
|
||||
Camera* camera = g_base->graphics->camera();
|
||||
if (!handled && camera && camera->manual()) {
|
||||
if (camera && camera->manual()) {
|
||||
float move_h = (cursor_pos_x_ - old_cursor_pos_x)
|
||||
/ g_base->graphics->screen_virtual_width();
|
||||
float move_v = (cursor_pos_y_ - old_cursor_pos_y)
|
||||
/ g_base->graphics->screen_virtual_width();
|
||||
camera->ManualHandleMouseMove(move_h, move_v);
|
||||
}
|
||||
|
||||
// Old screen edge UI.
|
||||
g_base->ui->HandleLegacyRootUIMouseMotion(cursor_pos_x_, cursor_pos_y_);
|
||||
}
|
||||
|
||||
void Input::PushMouseDownEvent(int button, const Vector2f& position) {
|
||||
SafePushLogicCall(__func__, [this, button, position] {
|
||||
HandleMouseDown(button, position);
|
||||
});
|
||||
PushLogicCall(
|
||||
[this, button, position] { HandleMouseDown(button, position); });
|
||||
}
|
||||
|
||||
void Input::HandleMouseDown(int button, const Vector2f& position) {
|
||||
assert(g_base);
|
||||
assert(g_base->graphics);
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
MarkInputActive();
|
||||
|
||||
if (IsInputLocked()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// if (!g_base->ui->MainMenuVisible()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
MarkInputActive();
|
||||
|
||||
last_mouse_move_time_ = g_core->GetAppTimeMillisecs();
|
||||
mouse_move_count_++;
|
||||
|
||||
@ -1306,7 +1269,6 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
|
||||
last_click_time_ = click_time;
|
||||
|
||||
bool handled{};
|
||||
// auto* root_widget = g_base->ui->root_widget();
|
||||
|
||||
// If we have a touch-input in editing mode, pass along events to it.
|
||||
// (it usually handles its own events but here we want it to play nice
|
||||
@ -1317,15 +1279,8 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
if (g_base->ui->HandleLegacyRootUIMouseDown(cursor_pos_x_, cursor_pos_y_)) {
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
handled = g_base->ui->SendWidgetMessage(
|
||||
WidgetMessage(WidgetMessage::Type::kMouseDown, nullptr, cursor_pos_x_,
|
||||
cursor_pos_y_, double_click ? 2 : 1));
|
||||
handled = g_base->ui->HandleMouseDown(button, cursor_pos_x_, cursor_pos_y_,
|
||||
double_click);
|
||||
}
|
||||
|
||||
// Manual camera input.
|
||||
@ -1349,8 +1304,7 @@ void Input::HandleMouseDown(int button, const Vector2f& position) {
|
||||
}
|
||||
|
||||
void Input::PushMouseUpEvent(int button, const Vector2f& position) {
|
||||
SafePushLogicCall(
|
||||
__func__, [this, button, position] { HandleMouseUp(button, position); });
|
||||
PushLogicCall([this, button, position] { HandleMouseUp(button, position); });
|
||||
}
|
||||
|
||||
void Input::HandleMouseUp(int button, const Vector2f& position) {
|
||||
@ -1363,8 +1317,6 @@ void Input::HandleMouseUp(int button, const Vector2f& position) {
|
||||
cursor_pos_y_ = g_base->graphics->PixelToVirtualY(
|
||||
position.y * g_base->graphics->screen_pixel_height());
|
||||
|
||||
bool handled{};
|
||||
|
||||
// If we have a touch-input in editing mode, pass along events to it.
|
||||
// (it usually handles its own events but here we want it to play nice
|
||||
// with stuff under it by blocking touches, etc)
|
||||
@ -1373,14 +1325,7 @@ void Input::HandleMouseUp(int button, const Vector2f& position) {
|
||||
cursor_pos_y_);
|
||||
}
|
||||
|
||||
// ui_v1::Widget* root_widget = g_base->ui->root_widget();
|
||||
// if (root_widget) {
|
||||
handled = g_base->ui->SendWidgetMessage(WidgetMessage(
|
||||
WidgetMessage::Type::kMouseUp, nullptr, cursor_pos_x_, cursor_pos_y_));
|
||||
// }
|
||||
|
||||
Camera* camera = g_base->graphics->camera();
|
||||
if (!handled && camera) {
|
||||
if (Camera* camera = g_base->graphics->camera()) {
|
||||
switch (button) {
|
||||
case SDL_BUTTON_LEFT:
|
||||
camera->set_mouse_left_down(false);
|
||||
@ -1397,11 +1342,11 @@ void Input::HandleMouseUp(int button, const Vector2f& position) {
|
||||
camera->UpdateManualMode();
|
||||
}
|
||||
|
||||
g_base->ui->HandleLegacyRootUIMouseUp(cursor_pos_x_, cursor_pos_y_);
|
||||
g_base->ui->HandleMouseUp(button, cursor_pos_x_, cursor_pos_y_);
|
||||
}
|
||||
|
||||
void Input::PushTouchEvent(const TouchEvent& e) {
|
||||
SafePushLogicCall(__func__, [e, this] { HandleTouchEvent(e); });
|
||||
PushLogicCall([e, this] { HandleTouchEvent(e); });
|
||||
}
|
||||
|
||||
void Input::HandleTouchEvent(const TouchEvent& e) {
|
||||
@ -1501,19 +1446,19 @@ void Input::Draw(FrameDef* frame_def) {
|
||||
}
|
||||
|
||||
auto Input::IsCursorVisible() const -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
if (!g_base->ui) {
|
||||
if (!g_base) {
|
||||
return false;
|
||||
}
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Keeps mouse hidden to start with..
|
||||
// Keeps mouse hidden to start with.
|
||||
if (mouse_move_count_ < 2) {
|
||||
return false;
|
||||
}
|
||||
bool val;
|
||||
|
||||
// Show our cursor if any dialogs/windows are up or else if its been
|
||||
// moved very recently.
|
||||
// Show our cursor if any dialogs/windows are up or else if its been moved
|
||||
// very recently.
|
||||
if (g_base->ui->MainMenuVisible()) {
|
||||
val = (g_core->GetAppTimeMillisecs() - last_mouse_move_time_ < 5000);
|
||||
} else {
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
#include "ballistica/base/python/base_python.h"
|
||||
#include "ballistica/base/support/plus_soft.h"
|
||||
#include "ballistica/base/support/stdio_console.h"
|
||||
#include "ballistica/base/ui/console.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
#include "ballistica/shared/python/python_sys.h"
|
||||
|
||||
@ -63,11 +63,11 @@ void BasePlatformApple::DoOpenURL(const std::string& url) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void BasePlatformApple::QuitApp() {
|
||||
void BasePlatformApple::TerminateApp() {
|
||||
#if BA_OSTYPE_MACOS && BA_XCODE_BUILD && !BA_HEADLESS_BUILD
|
||||
core::AppleUtils::Quit(); // will post a cocoa terminate
|
||||
core::AppleUtils::TerminateApp();
|
||||
#else
|
||||
BasePlatform::QuitApp();
|
||||
BasePlatform::TerminateApp();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ class BasePlatformApple : public BasePlatform {
|
||||
void RestorePurchases() override;
|
||||
void PurchaseAck(const std::string& purchase,
|
||||
const std::string& order_id) override;
|
||||
void QuitApp() override;
|
||||
void TerminateApp() override;
|
||||
|
||||
void DoOpenURL(const std::string& url) override;
|
||||
|
||||
|
||||
@ -321,6 +321,11 @@ void BasePlatform::OnAppShutdown() { assert(g_base->InLogicThread()); }
|
||||
void BasePlatform::OnScreenSizeChange() { assert(g_base->InLogicThread()); }
|
||||
void BasePlatform::DoApplyAppConfig() { assert(g_base->InLogicThread()); }
|
||||
|
||||
void BasePlatform::QuitApp() { exit(g_base->return_value()); }
|
||||
void BasePlatform::TerminateApp() { exit(g_base->return_value()); }
|
||||
|
||||
auto BasePlatform::CanSoftQuit() -> bool { return false; }
|
||||
auto BasePlatform::CanBackQuit() -> bool { return false; }
|
||||
void BasePlatform::DoBackQuit() {}
|
||||
void BasePlatform::DoSoftQuit() {}
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -33,8 +33,35 @@ class BasePlatform {
|
||||
virtual void OnScreenSizeChange();
|
||||
virtual void DoApplyAppConfig();
|
||||
|
||||
/// Quit the app (can be immediate or via posting some high level event).
|
||||
virtual void QuitApp();
|
||||
/// Return whether this platform supports soft-quit. A soft quit is
|
||||
/// when the app is reset/backgrounded/etc. but remains running in case
|
||||
/// needed again. Generally this is the behavior on mobile apps.
|
||||
virtual auto CanSoftQuit() -> bool;
|
||||
|
||||
/// Implement soft-quit behavior. Will always be called in the logic
|
||||
/// thread. Make sure to also override CanBackQuit to reflect this being
|
||||
/// present. Note that when quitting the app yourself, you should use
|
||||
/// g_base->QuitApp(); do not call this directly.
|
||||
virtual void DoSoftQuit();
|
||||
|
||||
/// Return whether this platform supports back-quit. A back quit is a
|
||||
/// variation of soft-quit generally triggered by a back button, which may
|
||||
/// give different results in the OS. For example on Android this may
|
||||
/// result in jumping back to the previous Android activity instead of
|
||||
/// just ending the current one and dumping to the home screen as normal
|
||||
/// soft quit might do.
|
||||
virtual auto CanBackQuit() -> bool;
|
||||
|
||||
/// Implement back-quit behavior. Will always be called in the logic
|
||||
/// thread. Make sure to also override CanBackQuit to reflect this being
|
||||
/// present. Note that when quitting the app yourself, you should use
|
||||
/// g_base->QuitApp(); do not call this directly.
|
||||
virtual void DoBackQuit();
|
||||
|
||||
/// Terminate the app. This can be immediate or by posting some high
|
||||
/// level event. There should be nothing left to do in the engine at
|
||||
/// this point.
|
||||
virtual void TerminateApp();
|
||||
|
||||
#pragma mark IN APP PURCHASES --------------------------------------------------
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@
|
||||
#include "ballistica/base/app_mode/app_mode_empty.h"
|
||||
#include "ballistica/base/graphics/graphics_server.h"
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/base/platform/base_platform.h"
|
||||
#include "ballistica/base/python/base_python.h"
|
||||
#include "ballistica/base/python/support/python_context_call_runnable.h"
|
||||
#include "ballistica/base/support/stress_test.h"
|
||||
@ -511,45 +512,23 @@ static auto PyQuit(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
static const char* kwlist[] = {"soft", "back", nullptr};
|
||||
int soft = 0;
|
||||
int back = 0;
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|ii",
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "|pp",
|
||||
const_cast<char**>(kwlist), &soft, &back)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Log(LogLevel::kDebug,
|
||||
// "QUIT soft=" + std::to_string(soft) + " back=" + std::to_string(back));
|
||||
|
||||
// FIXME this should all just go through platform and/or app-adapter.
|
||||
|
||||
if (g_buildconfig.ostype_ios_tvos()) {
|
||||
// This should never be called on iOS
|
||||
Log(LogLevel::kError, "Quit called.");
|
||||
QuitType quit_type{};
|
||||
if (back) {
|
||||
if (!soft) {
|
||||
Log(LogLevel::kWarning,
|
||||
"Got soft=False back=True in quit() which is ambiguous.");
|
||||
}
|
||||
|
||||
bool handled = false;
|
||||
|
||||
// A few types get handled specially on Android.
|
||||
if (g_buildconfig.ostype_android()) {
|
||||
if (!handled && back) {
|
||||
// Back-quit simply synthesizes a back press.
|
||||
// Note to self: I remember this behaved slightly differently than
|
||||
// doing a soft quit but I should remind myself how.
|
||||
g_core->platform->AndroidSynthesizeBackPress();
|
||||
handled = true;
|
||||
}
|
||||
|
||||
if (!handled && soft) {
|
||||
// Soft-quit just kills our activity but doesn't run app shutdown.
|
||||
// Thus we'll be able to spin back up (reset to the main menu)
|
||||
// if the user re-launches us.
|
||||
g_core->platform->AndroidQuitActivity();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
// In all other cases, kick off a standard app shutdown.
|
||||
if (!handled) {
|
||||
g_base->logic->event_loop()->PushCall([] { g_base->logic->Shutdown(); });
|
||||
quit_type = QuitType::kBack;
|
||||
} else if (soft) {
|
||||
quit_type = QuitType::kSoft;
|
||||
} else {
|
||||
quit_type = QuitType::kHard;
|
||||
}
|
||||
g_base->QuitApp(quit_type);
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
@ -559,15 +538,18 @@ static PyMethodDef PyQuitDef = {
|
||||
(PyCFunction)PyQuit, // method
|
||||
METH_VARARGS | METH_KEYWORDS, // flags
|
||||
|
||||
"quit(soft: bool = False, back: bool = False) -> None\n"
|
||||
"quit(soft: bool = True, back: bool = False) -> None\n"
|
||||
"\n"
|
||||
"Quit the game.\n"
|
||||
"Quit the app.\n"
|
||||
"\n"
|
||||
"Category: **General Utility Functions**\n"
|
||||
"\n"
|
||||
"On systems like Android, 'soft' will end the activity but keep the\n"
|
||||
"app running.",
|
||||
};
|
||||
"On platforms such as mobile, a 'soft' quit may background and/or reset\n"
|
||||
"the app but keep it running. A 'back' quit is a special form of soft\n"
|
||||
"quit that may trigger different behavior in the OS. On Android, for\n"
|
||||
"example, a back-quit may simply jump to the previous Android activity,\n"
|
||||
"while a regular soft quit may just exit the current activity and dump\n"
|
||||
"the user at their home screen."};
|
||||
|
||||
// ----------------------------- apply_config ----------------------------------
|
||||
|
||||
|
||||
@ -218,6 +218,8 @@ void AppConfig::SetupEntries() {
|
||||
BoolEntry("Always Use Internal Keyboard", false);
|
||||
bool_entries_[BoolID::kShowFPS] = BoolEntry("Show FPS", false);
|
||||
bool_entries_[BoolID::kShowPing] = BoolEntry("Show Ping", false);
|
||||
bool_entries_[BoolID::kShowDevConsoleButton] =
|
||||
BoolEntry("Show Dev Console Button", false);
|
||||
bool_entries_[BoolID::kEnableTVBorder] =
|
||||
BoolEntry("TV Border", g_core->platform->IsRunningOnTV());
|
||||
bool_entries_[BoolID::kKeyboardP2Enabled] =
|
||||
|
||||
@ -64,6 +64,7 @@ class AppConfig {
|
||||
kAlwaysUseInternalKeyboard,
|
||||
kShowFPS,
|
||||
kShowPing,
|
||||
kShowDevConsoleButton,
|
||||
kEnableTVBorder,
|
||||
kKeyboardP2Enabled,
|
||||
kEnablePackageMods,
|
||||
|
||||
@ -6,6 +6,7 @@
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
|
||||
// Predeclare some types we use.
|
||||
|
||||
namespace ballistica::ui_v1 {
|
||||
class RootUI;
|
||||
class Widget;
|
||||
@ -13,10 +14,9 @@ class Widget;
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
/// 'Soft' interface to the ui_v1 feature-set, managed by base.
|
||||
/// Feature-sets listing ui_v1 as a soft requirement must limit their use of
|
||||
/// it to these methods and should be prepared to handle the not-present
|
||||
/// case.
|
||||
/// 'Soft' interface to the ui_v1 feature-set, managed by base. Feature-sets
|
||||
/// listing ui_v1 as a soft requirement must limit their use of it to these
|
||||
/// methods and should be prepared to handle the not-present case.
|
||||
class UIV1SoftInterface {
|
||||
public:
|
||||
virtual void DoHandleDeviceMenuPress(base::InputDevice* device) = 0;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#include "ballistica/base/ui/console.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
|
||||
#include "ballistica/base/app_mode/app_mode.h"
|
||||
#include "ballistica/base/audio/audio.h"
|
||||
@ -19,14 +19,14 @@
|
||||
namespace ballistica::base {
|
||||
|
||||
// How much of the screen the console covers when it is at full size.
|
||||
const float kConsoleSize = 0.9f;
|
||||
const float kConsoleZDepth = 0.0f;
|
||||
const int kConsoleLineLimit = 80;
|
||||
const int kStringBreakUpSize = 1950;
|
||||
const int kActivateKey1 = SDLK_BACKQUOTE;
|
||||
const int kActivateKey2 = SDLK_F2;
|
||||
const float kDevConsoleSize = 0.9f;
|
||||
const float kDevConsoleZDepth = 0.0f;
|
||||
const int kDevConsoleLineLimit = 80;
|
||||
const int kDevConsoleStringBreakUpSize = 1950;
|
||||
const int kDevConsoleActivateKey1 = SDLK_BACKQUOTE;
|
||||
const int kDevConsoleActivateKey2 = SDLK_F2;
|
||||
|
||||
Console::Console() {
|
||||
DevConsole::DevConsole() {
|
||||
assert(g_base->InLogicThread());
|
||||
std::string title = std::string("BallisticaKit ") + kEngineVersion + " ("
|
||||
+ std::to_string(kEngineBuildNumber) + ")";
|
||||
@ -42,15 +42,15 @@ Console::Console() {
|
||||
prompt_text_group_.set_text(">");
|
||||
}
|
||||
|
||||
Console::~Console() = default;
|
||||
DevConsole::~DevConsole() = default;
|
||||
|
||||
auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool {
|
||||
auto DevConsole::HandleKeyPress(const SDL_Keysym* keysym) -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// Handle our toggle buttons no matter whether we're active.
|
||||
switch (keysym->sym) {
|
||||
case kActivateKey1:
|
||||
case kActivateKey2: {
|
||||
case kDevConsoleActivateKey1:
|
||||
case kDevConsoleActivateKey2: {
|
||||
if (!g_buildconfig.demo_build() && !g_buildconfig.arcade_build()) {
|
||||
// (reset input so characters don't continue walking and stuff)
|
||||
g_base->input->ResetHoldStates();
|
||||
@ -111,9 +111,7 @@ auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool {
|
||||
case SDLK_KP_ENTER:
|
||||
case SDLK_RETURN: {
|
||||
if (!input_enabled_) {
|
||||
Log(LogLevel::kWarning,
|
||||
"Console input is not allowed until the app reaches the 'running' "
|
||||
"state.");
|
||||
Log(LogLevel::kWarning, "Console input is not allowed yet.");
|
||||
break;
|
||||
}
|
||||
input_history_position_ = 0;
|
||||
@ -121,7 +119,7 @@ auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool {
|
||||
last_line_.clear();
|
||||
lines_.clear();
|
||||
} else {
|
||||
PushCommand(input_string_);
|
||||
SubmitCommand_(input_string_);
|
||||
}
|
||||
input_history_.push_front(input_string_);
|
||||
if (input_history_.size() > 100) {
|
||||
@ -151,7 +149,7 @@ auto Console::HandleKeyPress(const SDL_Keysym* keysym) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
void Console::PushCommand(const std::string& command) {
|
||||
void DevConsole::SubmitCommand_(const std::string& command) {
|
||||
assert(g_base);
|
||||
g_base->logic->event_loop()->PushCall([command] {
|
||||
// These are always run in whichever context is 'visible'.
|
||||
@ -172,13 +170,25 @@ void Console::PushCommand(const std::string& command) {
|
||||
});
|
||||
}
|
||||
|
||||
void Console::EnableInput() {
|
||||
void DevConsole::EnableInput() {
|
||||
assert(g_base->InLogicThread());
|
||||
input_enabled_ = true;
|
||||
}
|
||||
|
||||
void Console::ToggleState() {
|
||||
void DevConsole::Dismiss() {
|
||||
assert(g_base->InLogicThread());
|
||||
if (state_ == State::kInactive) {
|
||||
return;
|
||||
}
|
||||
|
||||
state_prev_ = state_;
|
||||
state_ = State::kInactive;
|
||||
transition_start_ = g_core->GetAppTimeMillisecs();
|
||||
}
|
||||
|
||||
void DevConsole::ToggleState() {
|
||||
assert(g_base->InLogicThread());
|
||||
state_prev_ = state_;
|
||||
switch (state_) {
|
||||
case State::kInactive:
|
||||
state_ = State::kMini;
|
||||
@ -194,7 +204,7 @@ void Console::ToggleState() {
|
||||
transition_start_ = g_core->GetAppTimeMillisecs();
|
||||
}
|
||||
|
||||
auto Console::HandleTextEditing(const std::string& text) -> bool {
|
||||
auto DevConsole::HandleTextEditing(const std::string& text) -> bool {
|
||||
assert(g_base->InLogicThread());
|
||||
if (state_ == State::kInactive) {
|
||||
return false;
|
||||
@ -209,31 +219,32 @@ auto Console::HandleTextEditing(const std::string& text) -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Console::HandleKeyRelease(const SDL_Keysym* keysym) -> bool {
|
||||
auto DevConsole::HandleKeyRelease(const SDL_Keysym* keysym) -> bool {
|
||||
// Always absorb our activate keys.
|
||||
if (keysym->sym == kActivateKey1 || keysym->sym == kActivateKey2) {
|
||||
if (keysym->sym == kDevConsoleActivateKey1
|
||||
|| keysym->sym == kDevConsoleActivateKey2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Otherwise simply absorb all key-ups if we're active.
|
||||
// Otherwise absorb *all* key-ups when we're active.
|
||||
return state_ != State::kInactive;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma ide diagnostic ignored "LocalValueEscapesScope"
|
||||
|
||||
void Console::Print(const std::string& s_in) {
|
||||
void DevConsole::Print(const std::string& s_in) {
|
||||
assert(g_base->InLogicThread());
|
||||
std::string s = Utils::GetValidUTF8(s_in.c_str(), "cspr");
|
||||
last_line_ += s;
|
||||
std::vector<std::string> broken_up;
|
||||
g_base->text_graphics->BreakUpString(last_line_.c_str(), kStringBreakUpSize,
|
||||
&broken_up);
|
||||
g_base->text_graphics->BreakUpString(
|
||||
last_line_.c_str(), kDevConsoleStringBreakUpSize, &broken_up);
|
||||
|
||||
// Spit out all completed lines and keep the last one as lastline.
|
||||
for (size_t i = 0; i < broken_up.size() - 1; i++) {
|
||||
lines_.emplace_back(broken_up[i], g_core->GetAppTimeMillisecs());
|
||||
if (lines_.size() > kConsoleLineLimit) {
|
||||
if (lines_.size() > kDevConsoleLineLimit) {
|
||||
lines_.pop_front();
|
||||
}
|
||||
}
|
||||
@ -243,7 +254,7 @@ void Console::Print(const std::string& s_in) {
|
||||
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
void Console::Draw(RenderPass* pass) {
|
||||
void DevConsole::Draw(RenderPass* pass) {
|
||||
millisecs_t transition_ticks = 100;
|
||||
if ((transition_start_ != 0)
|
||||
&& (state_ != State::kInactive
|
||||
@ -257,27 +268,37 @@ void Console::Draw(RenderPass* pass) {
|
||||
if (state_ == State::kMini) {
|
||||
bottom = pass->virtual_height() - mini_size;
|
||||
} else {
|
||||
bottom = pass->virtual_height() - pass->virtual_height() * kConsoleSize;
|
||||
bottom =
|
||||
pass->virtual_height() - pass->virtual_height() * kDevConsoleSize;
|
||||
}
|
||||
if (g_core->GetAppTimeMillisecs() - transition_start_ < transition_ticks) {
|
||||
if (state_ == State::kMini) {
|
||||
bottom = pass->virtual_height() * (1.0f - ratio) + bottom * (ratio);
|
||||
} else if (state_ == State::kFull) {
|
||||
bottom =
|
||||
(pass->virtual_height() - pass->virtual_height() * kConsoleSize)
|
||||
* (ratio)
|
||||
+ (pass->virtual_height() - mini_size) * (1.0f - ratio);
|
||||
float from_height;
|
||||
if (state_prev_ == State::kMini) {
|
||||
from_height = pass->virtual_height() - mini_size;
|
||||
} else if (state_prev_ == State::kFull) {
|
||||
from_height =
|
||||
pass->virtual_height() - pass->virtual_height() * kDevConsoleSize;
|
||||
} else {
|
||||
bottom = pass->virtual_height() * ratio + bottom * (1.0f - ratio);
|
||||
from_height = pass->virtual_height();
|
||||
}
|
||||
float to_height;
|
||||
if (state_ == State::kMini) {
|
||||
to_height = pass->virtual_height() - mini_size;
|
||||
} else if (state_ == State::kFull) {
|
||||
to_height =
|
||||
pass->virtual_height() - pass->virtual_height() * kDevConsoleSize;
|
||||
} else {
|
||||
to_height = pass->virtual_height();
|
||||
}
|
||||
bottom = to_height * ratio + from_height * (1.0 - ratio);
|
||||
}
|
||||
{
|
||||
bg_mesh_.SetPositionAndSize(0, bottom, kConsoleZDepth,
|
||||
bg_mesh_.SetPositionAndSize(0, bottom, kDevConsoleZDepth,
|
||||
pass->virtual_width(),
|
||||
(pass->virtual_height() - bottom));
|
||||
stripe_mesh_.SetPositionAndSize(0, bottom + 15, kConsoleZDepth,
|
||||
stripe_mesh_.SetPositionAndSize(0, bottom + 15, kDevConsoleZDepth,
|
||||
pass->virtual_width(), 15);
|
||||
shadow_mesh_.SetPositionAndSize(0, bottom - 7, kConsoleZDepth,
|
||||
shadow_mesh_.SetPositionAndSize(0, bottom - 7, kDevConsoleZDepth,
|
||||
pass->virtual_width(), 7);
|
||||
SimpleComponent c(pass);
|
||||
c.SetTransparent(true);
|
||||
@ -304,7 +325,8 @@ void Console::Draw(RenderPass* pass) {
|
||||
for (int e = 0; e < elem_count; e++) {
|
||||
c.SetTexture(built_text_group_.GetElementTexture(e));
|
||||
c.PushTransform();
|
||||
c.Translate(pass->virtual_width() - 175.0f, bottom + 0, kConsoleZDepth);
|
||||
c.Translate(pass->virtual_width() - 175.0f, bottom + 0,
|
||||
kDevConsoleZDepth);
|
||||
c.Scale(0.5f, 0.5f, 0.5f);
|
||||
c.DrawMesh(built_text_group_.GetElementMesh(e));
|
||||
c.PopTransform();
|
||||
@ -313,7 +335,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
for (int e = 0; e < elem_count; e++) {
|
||||
c.SetTexture(title_text_group_.GetElementTexture(e));
|
||||
c.PushTransform();
|
||||
c.Translate(20.0f, bottom + 0, kConsoleZDepth);
|
||||
c.Translate(20.0f, bottom + 0, kDevConsoleZDepth);
|
||||
c.Scale(0.5f, 0.5f, 0.5f);
|
||||
c.DrawMesh(title_text_group_.GetElementMesh(e));
|
||||
c.PopTransform();
|
||||
@ -323,7 +345,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
c.SetTexture(prompt_text_group_.GetElementTexture(e));
|
||||
c.SetColor(1, 1, 1, 1);
|
||||
c.PushTransform();
|
||||
c.Translate(5.0f, bottom + 15.0f, kConsoleZDepth);
|
||||
c.Translate(5.0f, bottom + 15.0f, kDevConsoleZDepth);
|
||||
c.Scale(0.5f, 0.5f, 0.5f);
|
||||
c.DrawMesh(prompt_text_group_.GetElementMesh(e));
|
||||
c.PopTransform();
|
||||
@ -332,7 +354,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
for (int e = 0; e < elem_count; e++) {
|
||||
c.SetTexture(input_text_group_.GetElementTexture(e));
|
||||
c.PushTransform();
|
||||
c.Translate(15.0f, bottom + 15.0f, kConsoleZDepth);
|
||||
c.Translate(15.0f, bottom + 15.0f, kDevConsoleZDepth);
|
||||
c.Scale(0.5f, 0.5f, 0.5f);
|
||||
c.DrawMesh(input_text_group_.GetElementMesh(e));
|
||||
c.PopTransform();
|
||||
@ -350,7 +372,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
c.PushTransform();
|
||||
c.Translate(
|
||||
19.0f + g_base->text_graphics->GetStringWidth(input_string_) * 0.5f,
|
||||
bottom + 23.0f, kConsoleZDepth);
|
||||
bottom + 23.0f, kDevConsoleZDepth);
|
||||
c.Scale(5, 11, 1.0f);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1));
|
||||
c.PopTransform();
|
||||
@ -365,7 +387,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
c.SetColor(1, 1, 1, 1);
|
||||
float h = 0.5f
|
||||
* (g_base->graphics->screen_virtual_width()
|
||||
- (kStringBreakUpSize * draw_scale));
|
||||
- (kDevConsoleStringBreakUpSize * draw_scale));
|
||||
float v = bottom + 32.0f;
|
||||
if (!last_line_.empty()) {
|
||||
if (last_line_mesh_dirty_) {
|
||||
@ -379,7 +401,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
for (int e = 0; e < elem_count; e++) {
|
||||
c.SetTexture(last_line_mesh_group_->GetElementTexture(e));
|
||||
c.PushTransform();
|
||||
c.Translate(h, v + 2, kConsoleZDepth);
|
||||
c.Translate(h, v + 2, kDevConsoleZDepth);
|
||||
c.Scale(draw_scale, draw_scale);
|
||||
c.DrawMesh(last_line_mesh_group_->GetElementMesh(e));
|
||||
c.PopTransform();
|
||||
@ -391,7 +413,7 @@ void Console::Draw(RenderPass* pass) {
|
||||
for (int e = 0; e < elem_count; e++) {
|
||||
c.SetTexture(i->GetText().GetElementTexture(e));
|
||||
c.PushTransform();
|
||||
c.Translate(h, v + 2, kConsoleZDepth);
|
||||
c.Translate(h, v + 2, kDevConsoleZDepth);
|
||||
c.Scale(draw_scale, draw_scale);
|
||||
c.DrawMesh(i->GetText().GetElementMesh(e));
|
||||
c.PopTransform();
|
||||
@ -1,7 +1,7 @@
|
||||
// Released under the MIT License. See LICENSE for details.
|
||||
|
||||
#ifndef BALLISTICA_BASE_UI_CONSOLE_H_
|
||||
#define BALLISTICA_BASE_UI_CONSOLE_H_
|
||||
#ifndef BALLISTICA_BASE_UI_DEV_CONSOLE_H_
|
||||
#define BALLISTICA_BASE_UI_DEV_CONSOLE_H_
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
@ -12,22 +12,31 @@
|
||||
|
||||
namespace ballistica::base {
|
||||
|
||||
class Console {
|
||||
class DevConsole {
|
||||
public:
|
||||
Console();
|
||||
~Console();
|
||||
auto active() const -> bool { return (state_ != State::kInactive); }
|
||||
auto transition_start() const -> millisecs_t { return transition_start_; }
|
||||
DevConsole();
|
||||
~DevConsole();
|
||||
auto IsActive() const -> bool { return (state_ != State::kInactive); }
|
||||
auto HandleTextEditing(const std::string& text) -> bool;
|
||||
auto HandleKeyPress(const SDL_Keysym* keysym) -> bool;
|
||||
auto HandleKeyRelease(const SDL_Keysym* keysym) -> bool;
|
||||
auto transition_start() const -> millisecs_t { return transition_start_; }
|
||||
|
||||
/// Toggle between mini, fullscreen, and inactive.
|
||||
void ToggleState();
|
||||
|
||||
/// Tell the console to quietly go away no matter what state it is in.
|
||||
void Dismiss();
|
||||
|
||||
/// Print text to the console.
|
||||
void Print(const std::string& s_in);
|
||||
void Draw(RenderPass* pass);
|
||||
|
||||
/// Called when the console should start accepting Python command input.
|
||||
void EnableInput();
|
||||
|
||||
private:
|
||||
void PushCommand(const std::string& command);
|
||||
void SubmitCommand_(const std::string& command);
|
||||
enum class State { kInactive, kMini, kFull };
|
||||
ImageMesh bg_mesh_;
|
||||
ImageMesh stripe_mesh_;
|
||||
@ -40,6 +49,7 @@ class Console {
|
||||
bool input_text_dirty_{true};
|
||||
millisecs_t transition_start_{};
|
||||
State state_{State::kInactive};
|
||||
State state_prev_{State::kInactive};
|
||||
|
||||
class Message {
|
||||
public:
|
||||
@ -71,4 +81,4 @@ class Console {
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
#endif // BALLISTICA_BASE_UI_CONSOLE_H_
|
||||
#endif // BALLISTICA_BASE_UI_DEV_CONSOLE_H_
|
||||
@ -3,13 +3,16 @@
|
||||
#include "ballistica/base/ui/ui.h"
|
||||
|
||||
#include "ballistica/base/audio/audio.h"
|
||||
#include "ballistica/base/graphics/component/simple_component.h"
|
||||
#include "ballistica/base/input/device/keyboard_input.h"
|
||||
#include "ballistica/base/input/input.h"
|
||||
#include "ballistica/base/logic/logic.h"
|
||||
#include "ballistica/base/python/base_python.h"
|
||||
#include "ballistica/base/support/app_config.h"
|
||||
#include "ballistica/base/support/ui_v1_soft.h"
|
||||
#include "ballistica/base/ui/console.h"
|
||||
#include "ballistica/base/ui/dev_console.h"
|
||||
#include "ballistica/shared/foundation/event_loop.h"
|
||||
#include "ballistica/shared/foundation/inline.h"
|
||||
#include "ballistica/shared/generic/utils.h"
|
||||
|
||||
namespace ballistica::base {
|
||||
@ -17,9 +20,10 @@ namespace ballistica::base {
|
||||
static const int kUIOwnerTimeoutSeconds = 30;
|
||||
|
||||
UI::UI() {
|
||||
// Figure out our interface type.
|
||||
assert(g_core);
|
||||
|
||||
// Figure out our interface scale.
|
||||
|
||||
// Allow overriding via an environment variable.
|
||||
auto* ui_override = getenv("BA_UI_SCALE");
|
||||
if (ui_override) {
|
||||
@ -37,7 +41,7 @@ UI::UI() {
|
||||
if (!force_scale_) {
|
||||
// Use automatic val.
|
||||
if (g_core->IsVRMode() || g_core->platform->IsRunningOnTV()) {
|
||||
// VR and tv builds always use medium.
|
||||
// VR and TV modes always use medium.
|
||||
scale_ = UIScale::kMedium;
|
||||
} else {
|
||||
scale_ = g_core->platform->GetUIScale();
|
||||
@ -85,6 +89,8 @@ void UI::DoApplyAppConfig() {
|
||||
if (g_base->HaveUIV1()) {
|
||||
g_base->ui_v1()->DoApplyAppConfig();
|
||||
}
|
||||
show_dev_console_button_ =
|
||||
g_base->app_config->Resolve(AppConfig::BoolID::kShowDevConsoleButton);
|
||||
}
|
||||
|
||||
auto UI::MainMenuVisible() const -> bool {
|
||||
@ -114,36 +120,69 @@ auto UI::PartyWindowOpen() -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
void UI::HandleLegacyRootUIMouseMotion(float x, float y) {
|
||||
if (g_base->HaveUIV1()) {
|
||||
g_base->ui_v1()->HandleLegacyRootUIMouseMotion(x, y);
|
||||
auto UI::HandleMouseDown(int button, float x, float y, bool double_click)
|
||||
-> bool {
|
||||
bool handled{};
|
||||
|
||||
if (show_dev_console_button_ && button == 1) {
|
||||
float vx = g_base->graphics->screen_virtual_width();
|
||||
float vy = g_base->graphics->screen_virtual_height();
|
||||
if (InDevConsoleButton_(x, y)) {
|
||||
dev_console_button_pressed_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
auto UI::HandleLegacyRootUIMouseDown(float x, float y) -> bool {
|
||||
if (g_base->HaveUIV1()) {
|
||||
return g_base->ui_v1()->HandleLegacyRootUIMouseDown(x, y);
|
||||
}
|
||||
return false;
|
||||
if (!handled && g_base->HaveUIV1()) {
|
||||
handled = g_base->ui_v1()->HandleLegacyRootUIMouseDown(x, y);
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
handled = SendWidgetMessage(WidgetMessage(
|
||||
WidgetMessage::Type::kMouseDown, nullptr, x, y, double_click ? 2 : 1));
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
void UI::HandleMouseUp(int button, float x, float y) {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
SendWidgetMessage(
|
||||
WidgetMessage(WidgetMessage::Type::kMouseUp, nullptr, x, y));
|
||||
|
||||
if (dev_console_button_pressed_) {
|
||||
if (InDevConsoleButton_(x, y)) {
|
||||
if (auto* console = g_base->console()) {
|
||||
console->ToggleState();
|
||||
}
|
||||
}
|
||||
dev_console_button_pressed_ = false;
|
||||
}
|
||||
|
||||
void UI::HandleLegacyRootUIMouseUp(float x, float y) {
|
||||
if (g_base->HaveUIV1()) {
|
||||
g_base->ui_v1()->HandleLegacyRootUIMouseUp(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::HandleMouseMotion(float x, float y) {
|
||||
SendWidgetMessage(
|
||||
WidgetMessage(WidgetMessage::Type::kMouseMove, nullptr, x, y));
|
||||
|
||||
if (g_base->HaveUIV1()) {
|
||||
g_base->ui_v1()->HandleLegacyRootUIMouseMotion(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
void UI::PushBackButtonCall(InputDevice* input_device) {
|
||||
g_base->logic->event_loop()->PushCall([this, input_device] {
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// If there's a UI up, send along a cancel message.
|
||||
if (g_base->ui->MainMenuVisible()) {
|
||||
g_base->ui->SendWidgetMessage(
|
||||
WidgetMessage(WidgetMessage::Type::kCancel));
|
||||
if (MainMenuVisible()) {
|
||||
SendWidgetMessage(WidgetMessage(WidgetMessage::Type::kCancel));
|
||||
} else {
|
||||
// If there's no main screen or overlay windows, ask for a menu owned by
|
||||
// this device.
|
||||
// If there's no main screen or overlay windows, ask for a menu owned
|
||||
// by this device.
|
||||
MainMenuPress_(input_device);
|
||||
}
|
||||
});
|
||||
@ -173,24 +212,6 @@ void UI::SetUIInputDevice(InputDevice* input_device) {
|
||||
last_input_device_use_time_ = g_core->GetAppTimeMillisecs();
|
||||
}
|
||||
|
||||
UI::UILock::UILock(bool write) {
|
||||
assert(g_base->ui);
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
if (write && g_base->ui->ui_lock_count_ != 0) {
|
||||
BA_LOG_ERROR_TRACE_ONCE("Illegal operation: UI is locked");
|
||||
}
|
||||
g_base->ui->ui_lock_count_++;
|
||||
}
|
||||
|
||||
UI::UILock::~UILock() {
|
||||
g_base->ui->ui_lock_count_--;
|
||||
if (g_base->ui->ui_lock_count_ < 0) {
|
||||
BA_LOG_ERROR_TRACE_ONCE("ui_lock_count_ < 0");
|
||||
g_base->ui->ui_lock_count_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void UI::Reset() {
|
||||
if (g_base->HaveUIV1()) {
|
||||
g_base->ui_v1()->Reset();
|
||||
@ -198,9 +219,9 @@ void UI::Reset() {
|
||||
}
|
||||
|
||||
auto UI::ShouldHighlightWidgets() const -> bool {
|
||||
// Show selection highlights only if we've got controllers connected and only
|
||||
// when the main UI is visible (dont want a selection highlight for toolbar
|
||||
// buttons during a game).
|
||||
// Show selection highlights only if we've got controllers connected and
|
||||
// only when the main UI is visible (dont want a selection highlight for
|
||||
// toolbar buttons during a game).
|
||||
return g_base->input->have_non_touch_inputs() && MainMenuVisible();
|
||||
}
|
||||
|
||||
@ -236,22 +257,24 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
||||
assert(input_device);
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
// We only allow input-devices to control the UI when there's a window/dialog
|
||||
// on the screen (even though our top/bottom bars still exist).
|
||||
// We only allow input-devices to control the UI when there's a
|
||||
// window/dialog on the screen (even though our top/bottom bars still
|
||||
// exist).
|
||||
if (!MainMenuVisible()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
millisecs_t time = g_core->GetAppTimeMillisecs();
|
||||
|
||||
bool print_menu_owner = false;
|
||||
bool print_menu_owner{};
|
||||
ui_v1::Widget* ret_val;
|
||||
|
||||
// Ok here's the deal:
|
||||
// Because having 10 controllers attached to the UI is pure chaos,
|
||||
// we only allow one input device at a time to control the menu.
|
||||
// However, if no events are received by that device for a long time,
|
||||
// it is up for grabs to the next device that requests it.
|
||||
//
|
||||
// Because having 10 controllers attached to the UI is pure chaos, we only
|
||||
// allow one input device at a time to control the menu. However, if no
|
||||
// events are received by that device for a long time, it is up for grabs
|
||||
// to the next device that requests it.
|
||||
|
||||
if (!g_base->HaveUIV1()) {
|
||||
ret_val = nullptr;
|
||||
@ -265,7 +288,6 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
||||
// seconds ago to automatically own a newly created widget).
|
||||
last_input_device_use_time_ = time;
|
||||
ui_input_device_ = input_device;
|
||||
// ret_val = screen_root_widget_.Get();
|
||||
ret_val = g_base->ui_v1()->GetRootWidget();
|
||||
} else {
|
||||
// For rejected input devices, play error sounds sometimes so they know
|
||||
@ -301,8 +323,8 @@ auto UI::GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget* {
|
||||
} else if (input->GetDeviceName() == "TouchScreen") {
|
||||
name = g_base->assets->GetResourceString("touchScreenText");
|
||||
} else {
|
||||
// We used to use player names here, but that's kinda sloppy and random;
|
||||
// lets just go with device names/numbers.
|
||||
// We used to use player names here, but that's kinda sloppy and
|
||||
// random; lets just go with device names/numbers.
|
||||
auto devicesWithName =
|
||||
g_base->input->GetInputDevicesWithName(input->GetDeviceName());
|
||||
if (devicesWithName.size() == 1) {
|
||||
@ -328,6 +350,82 @@ void UI::Draw(FrameDef* frame_def) {
|
||||
}
|
||||
}
|
||||
|
||||
void UI::DrawDev(FrameDef* frame_def) {
|
||||
// Draw dev console.
|
||||
if (g_base->console()) {
|
||||
g_base->console()->Draw(frame_def->overlay_pass());
|
||||
}
|
||||
|
||||
// Draw dev console button.
|
||||
if (show_dev_console_button_) {
|
||||
DrawDevConsoleButton_(frame_def);
|
||||
}
|
||||
}
|
||||
|
||||
auto UI::DevConsoleButtonSize_() const -> float {
|
||||
if (scale_ == UIScale::kLarge) {
|
||||
return 25.0f;
|
||||
} else if (scale_ == UIScale::kMedium) {
|
||||
return 40.0f;
|
||||
}
|
||||
return 60.0f;
|
||||
}
|
||||
|
||||
auto UI::InDevConsoleButton_(float x, float y) const -> bool {
|
||||
float vwidth = g_base->graphics->screen_virtual_width();
|
||||
float vheight = g_base->graphics->screen_virtual_height();
|
||||
float bsz = DevConsoleButtonSize_();
|
||||
float bszh = bsz * 0.5f;
|
||||
float centerx = vwidth - bsz * 0.5f;
|
||||
float centery = vheight * 0.5f - bsz * 0.5f;
|
||||
float diffx = ::std::abs(centerx - x);
|
||||
float diffy = ::std::abs(centery - y);
|
||||
return diffx <= bszh && diffy <= bszh;
|
||||
}
|
||||
|
||||
void UI::DrawDevConsoleButton_(FrameDef* frame_def) {
|
||||
if (!dev_console_button_txt_.Exists()) {
|
||||
dev_console_button_txt_ = Object::New<TextGroup>();
|
||||
dev_console_button_txt_->set_text("dev");
|
||||
}
|
||||
auto& grp(*dev_console_button_txt_);
|
||||
float vwidth = g_base->graphics->screen_virtual_width();
|
||||
float vheight = g_base->graphics->screen_virtual_height();
|
||||
float bsz = DevConsoleButtonSize_();
|
||||
|
||||
SimpleComponent c(frame_def->overlay_pass());
|
||||
c.SetTransparent(true);
|
||||
if (dev_console_button_pressed_) {
|
||||
c.SetColor(1.0f, 1.0f, 1.0f, 0.8f);
|
||||
} else {
|
||||
c.SetColor(0.5f, 0.5f, 0.5f, 0.8f);
|
||||
}
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Translate(vwidth - bsz * 0.5f, vheight * 0.5f - bsz * 0.5f,
|
||||
kCursorZDepth - 0.01f);
|
||||
c.Scale(bsz, bsz, 1.0f);
|
||||
c.DrawMeshAsset(g_base->assets->SysMesh(SysMeshID::kImage1x1));
|
||||
{
|
||||
auto xf = c.ScopedTransform();
|
||||
c.Scale(0.02f, 0.02f, 1.0f);
|
||||
c.Translate(-20.0f, -15.0f, 0.0f);
|
||||
int text_elem_count = grp.GetElementCount();
|
||||
if (dev_console_button_pressed_) {
|
||||
c.SetColor(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
} else {
|
||||
c.SetColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
for (int e = 0; e < text_elem_count; e++) {
|
||||
c.SetTexture(grp.GetElementTexture(e));
|
||||
c.SetFlatness(1.0f);
|
||||
c.DrawMesh(grp.GetElementMesh(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
c.Submit();
|
||||
}
|
||||
|
||||
void UI::ShowURL(const std::string& url) {
|
||||
if (g_base->HaveUIV1()) {
|
||||
g_base->ui_v1()->DoShowURL(url);
|
||||
@ -339,15 +437,17 @@ void UI::ShowURL(const std::string& url) {
|
||||
|
||||
void UI::ConfirmQuit() {
|
||||
g_base->logic->event_loop()->PushCall([] {
|
||||
// If the in-app console is active, dismiss it.
|
||||
if (g_base->console() != nullptr && g_base->console()->IsActive()) {
|
||||
g_base->console()->Dismiss();
|
||||
}
|
||||
|
||||
assert(g_base->InLogicThread());
|
||||
// If we're headless or input is locked or the in-app-console is up or
|
||||
// we don't have ui-v1, just quit immediately; a confirm screen
|
||||
// wouldn't work anyway.
|
||||
// If we're headless or we don't have ui-v1, just quit immediately; a
|
||||
// confirm screen wouldn't work anyway.
|
||||
if (g_core->HeadlessMode() || g_base->input->IsInputLocked()
|
||||
|| !g_base->HaveUIV1()
|
||||
|| (g_base->console() != nullptr && g_base->console()->active())) {
|
||||
g_base->logic->Shutdown();
|
||||
// g_base->python->objs().Get(BasePython::ObjID::kQuitCall).Call();
|
||||
|| !g_base->HaveUIV1()) {
|
||||
g_base->QuitApp();
|
||||
return;
|
||||
} else {
|
||||
ScopedSetContext ssc(nullptr);
|
||||
|
||||
@ -10,19 +10,6 @@
|
||||
#include "ballistica/base/ui/widget_message.h"
|
||||
#include "ballistica/shared/generic/timer_list.h"
|
||||
|
||||
// UI-Locks: make sure widget-lists don't change under you. Use a read-lock
|
||||
// if you just need to ensure lists remain intact but won't be changing
|
||||
// anything. Use a write-lock whenever modifying a list.
|
||||
#if BA_DEBUG_BUILD
|
||||
#define BA_DEBUG_UI_READ_LOCK ::ballistica::base::UI::UILock ui_lock(false)
|
||||
#define BA_DEBUG_UI_WRITE_LOCK ::ballistica::base::UI::UILock ui_lock(true)
|
||||
#else
|
||||
#define BA_DEBUG_UI_READ_LOCK
|
||||
#define BA_DEBUG_UI_WRITE_LOCK
|
||||
#endif
|
||||
#define BA_UI_READ_LOCK UI::UILock ui_lock(false)
|
||||
#define BA_UI_WRITE_LOCK UI::UILock ui_lock(true)
|
||||
|
||||
// Predeclare a few things from ui_v1.
|
||||
namespace ballistica::ui_v1 {
|
||||
class Widget;
|
||||
@ -46,14 +33,17 @@ class UI {
|
||||
|
||||
void LanguageChanged();
|
||||
|
||||
/// Reset all UI to a default state. Generally should be called when
|
||||
/// switching app-modes or when resetting things within an app mode.
|
||||
void Reset();
|
||||
|
||||
/// Pop up an in-app window to show a url (NOT in a browser). Can be
|
||||
/// called from any thread.
|
||||
/// Pop up an in-app window to display a URL (NOT to open the URL in a
|
||||
/// browser). Can be called from any thread.
|
||||
void ShowURL(const std::string& url);
|
||||
|
||||
/// High level call to request a quit ui. When a UI can't be shown,
|
||||
/// triggers an immediate shutdown. This can be called from any thread.
|
||||
/// High level call to request a quit; ideally with a confirmation ui.
|
||||
/// When a UI can't be shown, triggers an immediate shutdown. This can be
|
||||
/// called from any thread.
|
||||
void ConfirmQuit();
|
||||
|
||||
/// Return whether there is UI present in either the main or overlay
|
||||
@ -61,66 +51,65 @@ class UI {
|
||||
auto MainMenuVisible() const -> bool;
|
||||
|
||||
auto PartyIconVisible() -> bool;
|
||||
void ActivatePartyIcon();
|
||||
void HandleLegacyRootUIMouseMotion(float x, float y);
|
||||
auto HandleLegacyRootUIMouseDown(float x, float y) -> bool;
|
||||
void HandleLegacyRootUIMouseUp(float x, float y);
|
||||
auto PartyWindowOpen() -> bool;
|
||||
void ActivatePartyIcon();
|
||||
|
||||
auto HandleMouseDown(int button, float x, float y, bool double_click) -> bool;
|
||||
void HandleMouseUp(int button, float x, float y);
|
||||
void HandleMouseMotion(float x, float y);
|
||||
|
||||
/// Draw regular UI.
|
||||
void Draw(FrameDef* frame_def);
|
||||
|
||||
// Returns the widget an input should send commands to, if any. Also
|
||||
// potentially locks other inputs out of controlling the UI, so only call
|
||||
// this if you intend on sending a message to that widget.
|
||||
/// Draw dev UI on top.
|
||||
void DrawDev(FrameDef* frame_def);
|
||||
|
||||
/// Return the widget an input-device should send commands to, if any.
|
||||
/// Potentially assigns UI control to the provide device, so only call
|
||||
/// this if you intend on actually sending a message to that widget.
|
||||
auto GetWidgetForInput(InputDevice* input_device) -> ui_v1::Widget*;
|
||||
|
||||
// Send message to the active widget.
|
||||
/// Send a message to the active widget.
|
||||
auto SendWidgetMessage(const WidgetMessage& msg) -> int;
|
||||
|
||||
/// Set the device controlling the UI.
|
||||
void SetUIInputDevice(InputDevice* input_device);
|
||||
|
||||
// Returns the input-device that currently owns the menu; otherwise
|
||||
// nullptr.
|
||||
/// Return the input-device that currently owns the UI; otherwise nullptr.
|
||||
auto GetUIInputDevice() const -> InputDevice*;
|
||||
|
||||
/// Schedule a back button press. Can be called from any thread.
|
||||
void PushBackButtonCall(InputDevice* input_device);
|
||||
|
||||
// Returns whether currently selected widgets should flash. This will be
|
||||
// false in some situations such as when only touch screen control is
|
||||
// active.
|
||||
/// Return whether currently selected widgets should flash. This will be
|
||||
/// false in some situations such as when only touch screen control is
|
||||
/// present.
|
||||
auto ShouldHighlightWidgets() const -> bool;
|
||||
|
||||
// Same except for button shortcuts; these generally only get shown if a
|
||||
// joystick of some form is present.
|
||||
/// Return whether currently selected widget should show button shortcuts.
|
||||
/// These generally only get shown if a joystick of some form is present.
|
||||
auto ShouldShowButtonShortcuts() const -> bool;
|
||||
|
||||
// Used to ensure widgets are not created or destroyed at certain times
|
||||
// (while traversing widget hierarchy, etc).
|
||||
class UILock {
|
||||
public:
|
||||
explicit UILock(bool write);
|
||||
~UILock();
|
||||
|
||||
private:
|
||||
BA_DISALLOW_CLASS_COPIES(UILock);
|
||||
};
|
||||
|
||||
/// Overall ui scale for the app.
|
||||
auto scale() const { return scale_; }
|
||||
|
||||
/// Push a generic 'menu press' event, optionally associated with an
|
||||
/// input device (nullptr to specify none). Note: caller must ensure
|
||||
/// a RemoveInputDevice() call does not arrive at the logic thread
|
||||
/// before this one.
|
||||
/// Push a generic 'menu press' event, optionally associated with an input
|
||||
/// device (nullptr to specify none). Can be called from any thread.
|
||||
void PushMainMenuPressCall(InputDevice* device);
|
||||
|
||||
private:
|
||||
void MainMenuPress_(InputDevice* device);
|
||||
auto DevConsoleButtonSize_() const -> float;
|
||||
auto InDevConsoleButton_(float x, float y) const -> bool;
|
||||
void DrawDevConsoleButton_(FrameDef* frame_def);
|
||||
Object::WeakRef<InputDevice> ui_input_device_;
|
||||
millisecs_t last_input_device_use_time_{};
|
||||
millisecs_t last_widget_input_reject_err_sound_time_{};
|
||||
int ui_lock_count_{};
|
||||
UIScale scale_{UIScale::kLarge};
|
||||
bool force_scale_{};
|
||||
bool show_dev_console_button_{};
|
||||
bool dev_console_button_pressed_{};
|
||||
Object::Ref<TextGroup> dev_console_button_txt_;
|
||||
};
|
||||
|
||||
} // namespace ballistica::base
|
||||
|
||||
@ -682,14 +682,6 @@ void CorePlatform::AndroidSetResString(const std::string& res) {
|
||||
throw Exception();
|
||||
}
|
||||
|
||||
void CorePlatform::AndroidSynthesizeBackPress() {
|
||||
Log(LogLevel::kError, "AndroidSynthesizeBackPress() unimplemented");
|
||||
}
|
||||
|
||||
void CorePlatform::AndroidQuitActivity() {
|
||||
Log(LogLevel::kError, "AndroidQuitActivity() unimplemented");
|
||||
}
|
||||
|
||||
auto CorePlatform::GetDeviceV1AccountID() -> std::string {
|
||||
if (g_core->HeadlessMode()) {
|
||||
return "S-" + GetLegacyDeviceUUID();
|
||||
@ -758,12 +750,6 @@ void CorePlatform::MusicPlayerSetVolume(float volume) {
|
||||
|
||||
auto CorePlatform::IsOSPlayingMusic() -> bool { return false; }
|
||||
|
||||
void CorePlatform::AndroidShowAppInvite(const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& code) {
|
||||
Log(LogLevel::kError, "AndroidShowAppInvite() unimplemented");
|
||||
}
|
||||
|
||||
void CorePlatform::IncrementAnalyticsCount(const std::string& name,
|
||||
int increment) {}
|
||||
|
||||
|
||||
@ -217,11 +217,6 @@ class CorePlatform {
|
||||
|
||||
virtual auto GetAndroidExecArg() -> std::string;
|
||||
virtual void AndroidSetResString(const std::string& res);
|
||||
virtual void AndroidSynthesizeBackPress();
|
||||
virtual void AndroidQuitActivity();
|
||||
virtual void AndroidShowAppInvite(const std::string& title,
|
||||
const std::string& message,
|
||||
const std::string& code);
|
||||
virtual auto AndroidGetExternalFilesDir() -> std::string;
|
||||
|
||||
#pragma mark PERMISSIONS -------------------------------------------------------
|
||||
|
||||
@ -2,3 +2,8 @@
|
||||
|
||||
Gameplay code for classic BombSquad, as well as app-modes and other support
|
||||
classes required to use it.
|
||||
|
||||
Note that, ideally, gameplay code (scene version) should live in its own feature
|
||||
set and app-mode code should live in another. That way a single app-mode can
|
||||
wrangle multiple scene versions. But for historical reasons they're all mixed up
|
||||
in this case.
|
||||
|
||||
@ -71,7 +71,9 @@ auto ImageNode::InitType() -> NodeType* {
|
||||
ImageNode::ImageNode(Scene* scene) : Node(scene, node_type) {}
|
||||
|
||||
ImageNode::~ImageNode() {
|
||||
if (fill_screen_) scene()->decrement_bg_cover_count();
|
||||
if (fill_screen_) {
|
||||
scene()->decrement_bg_cover_count();
|
||||
}
|
||||
}
|
||||
|
||||
auto ImageNode::GetAttach() const -> std::string {
|
||||
@ -209,11 +211,11 @@ void ImageNode::Draw(base::FrameDef* frame_def) {
|
||||
if (host_only_ && !context_ref().GetHostSession()) {
|
||||
return;
|
||||
}
|
||||
bool vr = (g_core->IsVRMode());
|
||||
bool vr = g_core->IsVRMode();
|
||||
|
||||
// In vr mode we use the fixed overlay position if our scene
|
||||
// is set for that.
|
||||
bool vr_use_fixed = (scene()->use_fixed_vr_overlay());
|
||||
bool vr_use_fixed = scene()->use_fixed_vr_overlay();
|
||||
|
||||
// Currently front and vr-fixed are mutually-exclusive.. need to fix.
|
||||
if (front_) {
|
||||
|
||||
@ -39,11 +39,10 @@ const int kKickVoteFailRetryDelay = 60000;
|
||||
/// Extra delay for the initiator of a failed vote.
|
||||
const int kKickVoteFailRetryDelayInitiatorExtra = 120000;
|
||||
|
||||
// Minimum clients that must be present for a kick vote to count.
|
||||
// (for non-headless builds we require more votes since the host doesn't count
|
||||
// but may be playing (in a 2on2 with 3 clients, don't want 2 clients able to
|
||||
// kick).
|
||||
// NOLINTNEXTLINE(cert-err58-cpp)
|
||||
// Minimum clients that must be present for a kick vote to count. (for
|
||||
// non-headless builds we require more votes since the host doesn't count
|
||||
// but may be playing (in a 2on2 with 3 clients, don't want 2 clients able
|
||||
// to kick).
|
||||
const int kKickVoteMinimumClients = (g_buildconfig.headless_build() ? 3 : 4);
|
||||
|
||||
struct SceneV1AppMode::ScanResultsEntryPriv {
|
||||
@ -68,7 +67,7 @@ base::InputDeviceDelegate* SceneV1AppMode::CreateInputDeviceDelegate(
|
||||
// Go with 5 minute ban.
|
||||
const int kKickBanSeconds = 5 * 60;
|
||||
|
||||
bool SceneV1AppMode::InMainMenu() const {
|
||||
bool SceneV1AppMode::InClassicMainMenuSession() const {
|
||||
HostSession* hostsession =
|
||||
ContextRefSceneV1::FromAppForegroundContext().GetHostSession();
|
||||
return (hostsession && hostsession->is_main_menu());
|
||||
|
||||
@ -150,15 +150,15 @@ class SceneV1AppMode : public base::AppMode {
|
||||
void OnAppStart() override;
|
||||
void OnAppPause() override;
|
||||
void OnAppResume() override;
|
||||
auto InMainMenu() const -> bool override;
|
||||
auto InClassicMainMenuSession() const -> bool override;
|
||||
auto CreateInputDeviceDelegate(base::InputDevice* device)
|
||||
-> base::InputDeviceDelegate* override;
|
||||
|
||||
void SetInternalMusic(base::SoundAsset* music, float volume = 1.0,
|
||||
bool loop = true);
|
||||
|
||||
// Run a cycle of host scanning (basically sending out a broadcast packet to
|
||||
// see who's out there).
|
||||
// Run a cycle of host scanning (basically sending out a broadcast packet
|
||||
// to see who's out there).
|
||||
void HostScanCycle();
|
||||
void EndHostScanning();
|
||||
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
|
||||
namespace ballistica::scene_v1 {
|
||||
|
||||
/// Wraps a weak-ref to a context_ref with functionality specific to scene_v1.
|
||||
/// A context-ref specific to SceneV1.
|
||||
class ContextRefSceneV1 : public base::ContextRef {
|
||||
public:
|
||||
ContextRefSceneV1() : ContextRef() {}
|
||||
@ -23,8 +23,8 @@ class ContextRefSceneV1 : public base::ContextRef {
|
||||
static auto FromAppForegroundContext() -> ContextRefSceneV1;
|
||||
|
||||
// If the current Context is (or is part of) a HostSession, return it;
|
||||
// otherwise return nullptr. be aware that this will return a session if the
|
||||
// context is *either* a host-activity or a host-session
|
||||
// otherwise return nullptr. be aware that this will return a session if
|
||||
// the context is *either* a host-activity or a host-session
|
||||
auto GetHostSession() const -> HostSession*;
|
||||
|
||||
// Return the current context as an HostActivity if it is one; otherwise
|
||||
@ -37,10 +37,9 @@ class ContextRefSceneV1 : public base::ContextRef {
|
||||
auto GetMutableScene() const -> Scene*;
|
||||
};
|
||||
|
||||
/// Object containing some sort of context_ref.
|
||||
/// App-modes can subclass this to provide the actual context_ref they desire,
|
||||
/// and then code can use GetTyped() to safely retrieve context_ref as that
|
||||
/// type.
|
||||
/// Object containing some sort of context_ref. App-modes can subclass this
|
||||
/// to provide the actual context_ref they desire, and then code can use
|
||||
/// GetTyped() to safely retrieve context_ref as that type.
|
||||
class SceneV1Context : public base::Context {
|
||||
public:
|
||||
static auto Current() -> SceneV1Context& {
|
||||
|
||||
@ -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 = 21306;
|
||||
const int kEngineBuildNumber = 21322;
|
||||
const char* kEngineVersion = "1.7.28";
|
||||
const int kEngineApiVersion = 8;
|
||||
|
||||
|
||||
@ -2472,45 +2472,6 @@ static PyMethodDef PyShowAd2Def = {
|
||||
"(internal)",
|
||||
};
|
||||
|
||||
// --------------------------- show_app_invite ---------------------------------
|
||||
|
||||
static auto PyShowAppInvite(PyObject* self, PyObject* args, PyObject* keywds)
|
||||
-> PyObject* {
|
||||
BA_PYTHON_TRY;
|
||||
std::string title;
|
||||
std::string message;
|
||||
std::string code;
|
||||
PyObject* title_obj;
|
||||
PyObject* message_obj;
|
||||
PyObject* code_obj;
|
||||
static const char* kwlist[] = {"title", "message", "code", nullptr};
|
||||
if (!PyArg_ParseTupleAndKeywords(args, keywds, "OOO",
|
||||
const_cast<char**>(kwlist), &title_obj,
|
||||
&message_obj, &code_obj)) {
|
||||
return nullptr;
|
||||
}
|
||||
title = g_base->python->GetPyLString(title_obj);
|
||||
message = g_base->python->GetPyLString(message_obj);
|
||||
code = g_base->python->GetPyLString(code_obj);
|
||||
g_core->platform->AndroidShowAppInvite(title, message, code);
|
||||
Py_RETURN_NONE;
|
||||
BA_PYTHON_CATCH;
|
||||
}
|
||||
|
||||
static PyMethodDef PyShowAppInviteDef = {
|
||||
"show_app_invite", // name
|
||||
(PyCFunction)PyShowAppInvite, // method
|
||||
METH_VARARGS | METH_KEYWORDS, // flags
|
||||
|
||||
"show_app_invite(title: str | bauiv1.Lstr,\n"
|
||||
" message: str | bauiv1.Lstr,\n"
|
||||
" code: str) -> None\n"
|
||||
"\n"
|
||||
"(internal)\n"
|
||||
"\n"
|
||||
"Category: **General Utility Functions**",
|
||||
};
|
||||
|
||||
// --------------------- set_party_icon_always_visible -------------------------
|
||||
|
||||
static auto PySetPartyIconAlwaysVisible(PyObject* self, PyObject* args,
|
||||
@ -2882,7 +2843,6 @@ auto PythonMethodsUIV1::GetMethods() -> std::vector<PyMethodDef> {
|
||||
PyGetSpecialWidgetDef,
|
||||
PySetPartyWindowOpenDef,
|
||||
PySetPartyIconAlwaysVisibleDef,
|
||||
PyShowAppInviteDef,
|
||||
PyShowAdDef,
|
||||
PyShowAd2Def,
|
||||
PyShowOnlineScoreUIDef,
|
||||
|
||||
@ -223,7 +223,7 @@ void RootUI::Draw(base::FrameDef* frame_def) {
|
||||
// Flash and show a message if we're in the main menu instructing the
|
||||
// player to start a game.
|
||||
bool flash = false;
|
||||
bool in_main_menu = g_base->app_mode()->InMainMenu();
|
||||
bool in_main_menu = g_base->app_mode()->InClassicMainMenuSession();
|
||||
|
||||
if (in_main_menu && party_size > 0 && show_client_joined) flash = true;
|
||||
|
||||
@ -255,8 +255,8 @@ void RootUI::Draw(base::FrameDef* frame_def) {
|
||||
c.PopTransform();
|
||||
c.Submit();
|
||||
|
||||
// Based on who has menu control, we may show a key/button below the party
|
||||
// icon.
|
||||
// Based on who has menu control, we may show a key/button below the
|
||||
// party icon.
|
||||
if (!active) {
|
||||
if (base::InputDevice* uiid = g_base->ui->GetUIInputDevice()) {
|
||||
std::string party_button_name = uiid->GetPartyButtonName();
|
||||
@ -304,8 +304,8 @@ void RootUI::Draw(base::FrameDef* frame_def) {
|
||||
party_size_text_group_->set_text(
|
||||
std::to_string(party_size_text_group_num_));
|
||||
|
||||
// ..we also may want to update our 'someone joined' message if we're
|
||||
// host
|
||||
// ..we also may want to update our 'someone joined' message if
|
||||
// we're host
|
||||
if (is_host) {
|
||||
if (!start_a_game_text_group_.Exists()) {
|
||||
start_a_game_text_group_ = Object::New<base::TextGroup>();
|
||||
|
||||
@ -134,9 +134,8 @@ void UIV1FeatureSet::Draw(base::FrameDef* frame_def) {
|
||||
auto* root_widget = root_widget_.Get();
|
||||
|
||||
if (root_widget && root_widget->HasChildren()) {
|
||||
// Draw our opaque and transparent parts separately.
|
||||
// This way we can draw front-to-back for opaque and back-to-front for
|
||||
// transparent.
|
||||
// Draw our opaque and transparent parts separately. This way we can
|
||||
// draw front-to-back for opaque and back-to-front for transparent.
|
||||
|
||||
g_base->graphics->set_drawing_opaque_only(true);
|
||||
|
||||
@ -281,4 +280,22 @@ void UIV1FeatureSet::DoApplyAppConfig() {
|
||||
base::AppConfig::BoolID::kAlwaysUseInternalKeyboard));
|
||||
}
|
||||
|
||||
UIV1FeatureSet::UILock::UILock(bool write) {
|
||||
assert(g_base->ui);
|
||||
assert(g_base->InLogicThread());
|
||||
|
||||
if (write && g_ui_v1->ui_lock_count_ != 0) {
|
||||
BA_LOG_ERROR_TRACE_ONCE("Illegal operation: UI is locked");
|
||||
}
|
||||
g_ui_v1->ui_lock_count_++;
|
||||
}
|
||||
|
||||
UIV1FeatureSet::UILock::~UILock() {
|
||||
g_ui_v1->ui_lock_count_--;
|
||||
if (g_ui_v1->ui_lock_count_ < 0) {
|
||||
BA_LOG_ERROR_TRACE_ONCE("ui_lock_count_ < 0");
|
||||
g_ui_v1->ui_lock_count_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ballistica::ui_v1
|
||||
|
||||
@ -15,6 +15,19 @@
|
||||
// BA 2.0 UI testing.
|
||||
#define BA_UI_V1_TOOLBAR_TEST 0
|
||||
|
||||
// UI-Locks: make sure widget-lists don't change under you. Use a read-lock
|
||||
// if you just need to ensure lists remain intact but won't be changing
|
||||
// anything. Use a write-lock whenever modifying a list.
|
||||
#if BA_DEBUG_BUILD
|
||||
#define BA_DEBUG_UI_READ_LOCK \
|
||||
::ballistica::ui_v1::UIV1FeatureSet::UILock ui_lock(false)
|
||||
#define BA_DEBUG_UI_WRITE_LOCK \
|
||||
::ballistica::ui_v1::UIV1FeatureSet::UILock ui_lock(true)
|
||||
#else
|
||||
#define BA_DEBUG_UI_READ_LOCK
|
||||
#define BA_DEBUG_UI_WRITE_LOCK
|
||||
#endif
|
||||
|
||||
// Predeclared types from other feature sets that we use.
|
||||
namespace ballistica::core {
|
||||
class CoreFeatureSet;
|
||||
@ -57,6 +70,17 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
|
||||
/// it. Basically a Python import statement.
|
||||
static auto Import() -> UIV1FeatureSet*;
|
||||
|
||||
/// Used to ensure widgets are not created or destroyed at certain times
|
||||
/// (while traversing widget hierarchy, etc).
|
||||
class UILock {
|
||||
public:
|
||||
explicit UILock(bool write);
|
||||
~UILock();
|
||||
|
||||
private:
|
||||
BA_DISALLOW_CLASS_COPIES(UILock);
|
||||
};
|
||||
|
||||
/// Called when our associated Python module is instantiated.
|
||||
static void OnModuleExec(PyObject* module);
|
||||
void DoHandleDeviceMenuPress(base::InputDevice* device) override;
|
||||
@ -113,6 +137,7 @@ class UIV1FeatureSet : public FeatureSetNativeComponent,
|
||||
Object::Ref<ContainerWidget> screen_root_widget_;
|
||||
Object::Ref<ContainerWidget> overlay_root_widget_;
|
||||
Object::Ref<RootWidget> root_widget_;
|
||||
int ui_lock_count_{};
|
||||
};
|
||||
|
||||
} // namespace ballistica::ui_v1
|
||||
|
||||
@ -98,9 +98,9 @@ struct RootWidget::Text {
|
||||
};
|
||||
|
||||
RootWidget::RootWidget() {
|
||||
// we enable a special 'single-depth-root' mode
|
||||
// in which we use most of our depth range for our first child
|
||||
// (our screen stack) and the small remaining bit for the rest
|
||||
// We enable a special 'single-depth-root' mode in which we use most of
|
||||
// our depth range for our first child (our screen stack) and the small
|
||||
// remaining bit for the rest.
|
||||
set_single_depth(true);
|
||||
set_single_depth_root(true);
|
||||
set_background(false);
|
||||
@ -110,7 +110,7 @@ RootWidget::~RootWidget() = default;
|
||||
|
||||
auto RootWidget::AddCover(float h_align, VAlign v_align, float x, float y,
|
||||
float w, float h, float o) -> RootWidget::Button* {
|
||||
// currently just not doing these in vr mode
|
||||
// Currently just not doing these in vr mode.
|
||||
if (g_core->IsVRMode()) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -132,9 +132,9 @@ auto RootWidget::AddCover(float h_align, VAlign v_align, float x, float y,
|
||||
|
||||
bd.visibility_mask =
|
||||
static_cast<uint32_t>(Widget::ToolbarVisibility::kMenuFullRoot);
|
||||
// when the user specifies no backing it means they intend to cover the screen
|
||||
// with a flat-ish window texture.. however this only applies to phone-size;
|
||||
// for other sizes we always draw a backing.
|
||||
// When the user specifies no backing it means they intend to cover the
|
||||
// screen with a flat-ish window texture.. however this only applies to
|
||||
// phone-size; for other sizes we always draw a backing.
|
||||
if (g_base->ui->scale() != UIScale::kSmall) {
|
||||
bd.visibility_mask |=
|
||||
static_cast<uint32_t>(Widget::ToolbarVisibility::kMenuFull);
|
||||
@ -352,7 +352,7 @@ void RootWidget::Setup() {
|
||||
}
|
||||
}
|
||||
|
||||
// widen this a bit in small mode so it just covers most of the top
|
||||
// Widen this a bit in small mode so it just covers most of the top
|
||||
// - that looks funny in medium/large mode though
|
||||
// if (g_ui->scale() == UIScale::kSmall) {
|
||||
// AddCover(0.5f, VAlign::kTop, 0.0f, 320.0f,
|
||||
@ -838,8 +838,8 @@ auto RootWidget::AddButton(const ButtonDef& def) -> RootWidget::Button* {
|
||||
} else {
|
||||
b.widget->set_up_widget(screen_stack_widget_);
|
||||
}
|
||||
// We wanna prevent anyone from redirecting these to point to outside widgets
|
||||
// since we'll probably outlive those outside widgets.
|
||||
// We wanna prevent anyone from redirecting these to point to outside
|
||||
// widgets since we'll probably outlive those outside widgets.
|
||||
b.widget->set_neighbors_locked(true);
|
||||
|
||||
if (!def.img.empty()) {
|
||||
@ -894,7 +894,7 @@ void RootWidget::UpdateForFocusedWindow() {
|
||||
void RootWidget::UpdateForFocusedWindow(Widget* widget) {
|
||||
// Take note if the current session is the main menu; we do a few things
|
||||
// differently there.
|
||||
in_main_menu_ = g_base->app_mode()->InMainMenu();
|
||||
in_main_menu_ = g_base->app_mode()->InClassicMainMenuSession();
|
||||
|
||||
if (widget == nullptr) {
|
||||
toolbar_visibility_ = ToolbarVisibility::kInGame;
|
||||
@ -929,8 +929,8 @@ void RootWidget::StepPositions(float dt) {
|
||||
static_cast<bool>(static_cast<uint32_t>(toolbar_visibility_)
|
||||
& static_cast<uint32_t>(b.visibility_mask));
|
||||
|
||||
// When we're in the main menu, always disable the menu button
|
||||
// and shift the party button a bit to the right
|
||||
// When we're in the main menu, always disable the menu button and shift
|
||||
// the party button a bit to the right
|
||||
if (in_main_menu_) {
|
||||
if (&b == menu_button_) {
|
||||
enable_button = false;
|
||||
@ -940,13 +940,13 @@ void RootWidget::StepPositions(float dt) {
|
||||
}
|
||||
}
|
||||
if (&b == back_button_) {
|
||||
// back button is always disabled in medium/large UI
|
||||
// Back button is always disabled in medium/large UI.
|
||||
if (g_base->ui->scale() != UIScale::kSmall) {
|
||||
enable_button = false;
|
||||
}
|
||||
|
||||
// whenever back button is enabled, left on account button should go to
|
||||
// it; otherwise it goes nowhere.
|
||||
// Whenever back button is enabled, left on account button should go
|
||||
// to it; otherwise it goes nowhere.
|
||||
Widget* ab = account_button_->widget.Get();
|
||||
ab->set_neighbors_locked(false);
|
||||
ab->set_left_widget(enable_button ? back_button_->widget.Get() : ab);
|
||||
@ -957,9 +957,10 @@ void RootWidget::StepPositions(float dt) {
|
||||
b.y_target += disable_offset;
|
||||
}
|
||||
|
||||
// special case: we shift buttons on the top right to the right if the menu
|
||||
// button is hidden (and also if the button is hidden; otherwise things come
|
||||
// in diagonally)
|
||||
// special case: we shift buttons on the top right to the right if the
|
||||
// menu button is hidden (and also if the button is hidden; otherwise
|
||||
// things come in diagonally)
|
||||
//
|
||||
// if (b.h_align == HAlign::kRight and b.v_align == VAlign::kTop
|
||||
// if (b.h_align >= 1.0f and b.v_align == VAlign::kTop
|
||||
// and (toolbar_visibility_ != ToolbarVisibility::kInGame or not
|
||||
@ -971,15 +972,15 @@ void RootWidget::StepPositions(float dt) {
|
||||
b.x_smoothed += (b.x_target - b.x_smoothed) * 0.015f * dt;
|
||||
b.y_smoothed += (b.y_target - b.y_smoothed) * 0.015f * dt;
|
||||
|
||||
// Snap in place once we reach the target; otherwise note
|
||||
// that we need to keep going.
|
||||
// Snap in place once we reach the target; otherwise note that we need
|
||||
// to keep going.
|
||||
if (std::abs(b.x_target - b.x_smoothed) < 0.1f
|
||||
&& std::abs(b.y_target - b.y_smoothed) < 0.1f) {
|
||||
b.x_smoothed = b.x_target;
|
||||
b.y_smoothed = b.y_target;
|
||||
|
||||
// Also flip off visibility if we're moving offscreen and have reached our
|
||||
// target.
|
||||
// Also flip off visibility if we're moving offscreen and have reached
|
||||
// our target.
|
||||
if (!enable_button) {
|
||||
b.widget->set_visible_in_container(false);
|
||||
}
|
||||
@ -989,7 +990,8 @@ void RootWidget::StepPositions(float dt) {
|
||||
b.widget->set_visible_in_container(true);
|
||||
}
|
||||
|
||||
// Now calc final abs x and y based on screen size, smoothed positions, etc.
|
||||
// Now calc final abs x and y based on screen size, smoothed positions,
|
||||
// etc.
|
||||
float x, y;
|
||||
x = width() * b.h_align
|
||||
+ base_scale_ * (b.x_smoothed - b.width * b.scale * 0.5f);
|
||||
|
||||
@ -531,9 +531,9 @@ auto TextWidget::ShouldUseStringEditDialog() const -> bool {
|
||||
return true;
|
||||
}
|
||||
|
||||
// On most platforms we always want to do this.
|
||||
// on mac/pc, however, we use inline editing if the current UI input-device
|
||||
// is the mouse or keyboard
|
||||
// On most platforms we always want to do this. On desktop, however, we
|
||||
// use inline editing if the current UI input-device is the mouse or
|
||||
// keyboard.
|
||||
if (g_buildconfig.ostype_macos() || g_buildconfig.ostype_windows()
|
||||
|| g_buildconfig.ostype_linux()) {
|
||||
base::InputDevice* ui_input_device = g_base->ui->GetUIInputDevice();
|
||||
|
||||
@ -15,7 +15,7 @@ if TYPE_CHECKING:
|
||||
|
||||
|
||||
def generate_app_module(
|
||||
feature_sets: dict[str, FeatureSet], existing_data: str
|
||||
projroot: str, feature_sets: dict[str, FeatureSet], existing_data: str
|
||||
) -> str:
|
||||
"""Generate babase._app.py based on its existing version."""
|
||||
|
||||
@ -24,7 +24,7 @@ def generate_app_module(
|
||||
# pylint: disable=too-many-statements
|
||||
import textwrap
|
||||
|
||||
from efrotools import replace_section
|
||||
from efrotools import replace_section, getprojectconfig
|
||||
|
||||
out = ''
|
||||
|
||||
@ -156,31 +156,50 @@ def generate_app_module(
|
||||
|
||||
# Generate default app-mode-selection logic.
|
||||
# TODO - make this customizable via project settings or whatnot.
|
||||
default_app_modes: list[str] | None = getprojectconfig(projroot).get(
|
||||
'default_app_modes'
|
||||
)
|
||||
if not isinstance(default_app_modes, list) or not all(
|
||||
isinstance(x, str) for x in default_app_modes
|
||||
):
|
||||
raise RuntimeError(
|
||||
'Could not load default_app_modes from projectconfig'
|
||||
)
|
||||
|
||||
def _module_for_app_mode(amode: str) -> str:
|
||||
return '.'.join(amode.split('.')[:-1])
|
||||
|
||||
def _is_valid_app_mode(amode: str) -> bool:
|
||||
# Consider the app mode valid if it comes from a Python
|
||||
# package provided by one of our feature-sets.
|
||||
module = _module_for_app_mode(amode)
|
||||
for featureset in feature_sets.values():
|
||||
if featureset.name_python_package == module:
|
||||
return True
|
||||
return False
|
||||
|
||||
default_app_modes = [m for m in default_app_modes if _is_valid_app_mode(m)]
|
||||
contents = (
|
||||
'# Ask our default app modes to handle it.\n'
|
||||
"# (based on 'default_app_modes' in projectconfig).\n"
|
||||
"# (generated from 'default_app_modes' in projectconfig).\n"
|
||||
)
|
||||
imports: list[str] = []
|
||||
if 'scene_v1' in fsets:
|
||||
imports.append('bascenev1')
|
||||
if 'base' in fsets:
|
||||
imports.append('babase')
|
||||
|
||||
for imp in imports:
|
||||
contents += f'import {imp}\n'
|
||||
if not default_app_modes:
|
||||
raise RuntimeError('No valid default_app_modes specified.')
|
||||
|
||||
for mode in default_app_modes:
|
||||
contents += f'import {_module_for_app_mode(mode)}\n'
|
||||
contents += '\n'
|
||||
|
||||
if 'scene_v1' in fsets:
|
||||
contents += 'for appmode in [\n'
|
||||
for mode in default_app_modes:
|
||||
contents += f' {mode},\n'
|
||||
contents += (
|
||||
'if bascenev1.SceneV1AppMode.can_handle_intent(intent):\n'
|
||||
' return bascenev1.SceneV1AppMode\n\n'
|
||||
)
|
||||
if 'base' in fsets:
|
||||
contents += (
|
||||
'if babase.EmptyAppMode.can_handle_intent(intent):\n'
|
||||
' return babase.EmptyAppMode\n\n'
|
||||
']:\n'
|
||||
' if appmode.can_handle_intent(intent):\n'
|
||||
' return appmode\n'
|
||||
'\n'
|
||||
)
|
||||
|
||||
contents += 'return None\n'
|
||||
|
||||
indent = ' '
|
||||
|
||||
@ -699,7 +699,7 @@ class ProjectUpdater:
|
||||
from batools.appmodule import generate_app_module
|
||||
|
||||
self._generated_files[path] = generate_app_module(
|
||||
self.feature_sets, existing_data
|
||||
self.projroot, self.feature_sets, existing_data
|
||||
)
|
||||
|
||||
def _update_meta_makefile(self) -> None:
|
||||
|
||||
@ -28,6 +28,10 @@ PYVER = '3.11'
|
||||
# Update; just using the same executable used to launch us.
|
||||
PYTHON_BIN = sys.executable
|
||||
|
||||
# Cache these since we may repeatedly fetch these in batch mode.
|
||||
_g_project_configs: dict[str, dict[str, Any]] = {}
|
||||
_g_local_configs: dict[str, dict[str, Any]] = {}
|
||||
|
||||
|
||||
def explicit_bool(value: bool) -> bool:
|
||||
"""Simply return input value; can avoid unreachable-code type warnings."""
|
||||
@ -36,6 +40,8 @@ def explicit_bool(value: bool) -> bool:
|
||||
|
||||
def getlocalconfig(projroot: Path | str) -> dict[str, Any]:
|
||||
"""Return a project's localconfig contents (or default if missing)."""
|
||||
projrootstr = str(projroot)
|
||||
if projrootstr not in _g_local_configs:
|
||||
localconfig: dict[str, Any]
|
||||
|
||||
# Allow overriding path via env var.
|
||||
@ -48,11 +54,15 @@ def getlocalconfig(projroot: Path | str) -> dict[str, Any]:
|
||||
localconfig = json.loads(infile.read())
|
||||
except FileNotFoundError:
|
||||
localconfig = {}
|
||||
return localconfig
|
||||
_g_local_configs[projrootstr] = localconfig
|
||||
|
||||
return _g_local_configs[projrootstr]
|
||||
|
||||
|
||||
def getprojectconfig(projroot: Path | str) -> dict[str, Any]:
|
||||
"""Return a project's projectconfig contents (or default if missing)."""
|
||||
projrootstr = str(projroot)
|
||||
if projrootstr not in _g_project_configs:
|
||||
config: dict[str, Any]
|
||||
try:
|
||||
with open(
|
||||
@ -61,11 +71,14 @@ def getprojectconfig(projroot: Path | str) -> dict[str, Any]:
|
||||
config = json.loads(infile.read())
|
||||
except FileNotFoundError:
|
||||
config = {}
|
||||
return config
|
||||
_g_project_configs[projrootstr] = config
|
||||
return _g_project_configs[projrootstr]
|
||||
|
||||
|
||||
def setprojectconfig(projroot: Path | str, config: dict[str, Any]) -> None:
|
||||
"""Set the project config contents."""
|
||||
projrootstr = str(projroot)
|
||||
_g_project_configs[projrootstr] = config
|
||||
os.makedirs(Path(projroot, 'config'), exist_ok=True)
|
||||
with Path(projroot, 'config/projectconfig.json').open(
|
||||
'w', encoding='utf-8'
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user