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