diff --git a/.efrocachemap b/.efrocachemap index 424f0f95..01c50f06 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -421,40 +421,40 @@ "build/assets/ba_data/audio/zoeOw.ogg": "74befe45a8417e95b6a2233c51992a26", "build/assets/ba_data/audio/zoePickup01.ogg": "48ab8cddfcde36a750856f3f81dd20c8", "build/assets/ba_data/audio/zoeScream01.ogg": "2b468aedfa8741090247f04eb9e6df55", - "build/assets/ba_data/data/langdata.json": "65b989c0d893d8981992f66ff81a8a97", - "build/assets/ba_data/data/languages/arabic.json": "3be73283cb8009cc2c95e53df36e8b86", + "build/assets/ba_data/data/langdata.json": "fa2cb506dd6628e30b775ca44604e4f8", + "build/assets/ba_data/data/languages/arabic.json": "609f5d698a488e40e61787b62ee8ea5e", "build/assets/ba_data/data/languages/belarussian.json": "3d5523d0004293aa2df02f3f6f3b84f8", - "build/assets/ba_data/data/languages/chinese.json": "fc69790c41e6750d20a7719afc5a7527", - "build/assets/ba_data/data/languages/chinesetraditional.json": "86671be47e2b5d0badeb3b90a3db6402", + "build/assets/ba_data/data/languages/chinese.json": "d03ed49486d41cfbdf770e5a54f974a1", + "build/assets/ba_data/data/languages/chinesetraditional.json": "d85c58cc1e0e4bd0b09b2bc768cb1971", "build/assets/ba_data/data/languages/croatian.json": "b23619cb396ac16640c47458f884b16a", "build/assets/ba_data/data/languages/czech.json": "61bcfce75c0d53d2f2af709cee42187a", "build/assets/ba_data/data/languages/danish.json": "8e57db30c5250df2abff14a822f83ea7", "build/assets/ba_data/data/languages/dutch.json": "b0900d572c9141897d53d6574c471343", "build/assets/ba_data/data/languages/english.json": "5a73dea22df1117d58a79459def62ff5", "build/assets/ba_data/data/languages/esperanto.json": "0e397cfa5f3fb8cef5f4a64f21cda880", - "build/assets/ba_data/data/languages/filipino.json": "a291d4d3619adc82c5c4096bbfefe28a", - "build/assets/ba_data/data/languages/french.json": "73a01df9b44b3fb030750a1b5f56f07b", - "build/assets/ba_data/data/languages/german.json": "198b9860c5b9df7b8e3e30b03d8755cb", + "build/assets/ba_data/data/languages/filipino.json": "30f9622136067fe866bebf7e81ee8546", + "build/assets/ba_data/data/languages/french.json": "69578cc38349367912659a62ace5a42d", + "build/assets/ba_data/data/languages/german.json": "c4b8c4d3c078b7902155af3221cf9cf4", "build/assets/ba_data/data/languages/gibberish.json": "d6810f99fc9055b5203c382a83bc5128", "build/assets/ba_data/data/languages/greek.json": "d28d1092fbb00ed857cbd53124c0dc78", "build/assets/ba_data/data/languages/hindi.json": "54cd56bade6922b40989a8ac5e0c17f6", - "build/assets/ba_data/data/languages/hungarian.json": "3a974ea6e6ffccca41aed308ad5a7a26", - "build/assets/ba_data/data/languages/indonesian.json": "ed9038bf4b9216f93eb73e753e162706", - "build/assets/ba_data/data/languages/italian.json": "ffc58952260b63fdf88805a2d9a68257", + "build/assets/ba_data/data/languages/hungarian.json": "9d88004a98f0fbe2ea72edd5e0b3002e", + "build/assets/ba_data/data/languages/indonesian.json": "2ccb3fe081ead7706dbebb1008a8bc4e", + "build/assets/ba_data/data/languages/italian.json": "d9eb41f6eafb19040f8d5c0608790b62", "build/assets/ba_data/data/languages/korean.json": "4e3524327a0174250aff5e1ef4c0c597", "build/assets/ba_data/data/languages/malay.json": "f6ce0426d03a62612e3e436ed5d1be1f", "build/assets/ba_data/data/languages/persian.json": "ededb9c015afb58b1324a096ea740f72", - "build/assets/ba_data/data/languages/polish.json": "62b56ace320191985689bfbcfacd56ea", - "build/assets/ba_data/data/languages/portuguese.json": "2be5c25e55946197bd0e0f646d444b2c", + "build/assets/ba_data/data/languages/polish.json": "89333fb207f9eb2f22fff5a95b022c35", + "build/assets/ba_data/data/languages/portuguese.json": "eb2563e245e1ea00b870264dced3ebd7", "build/assets/ba_data/data/languages/romanian.json": "55a8744e466801013ea131266a856924", - "build/assets/ba_data/data/languages/russian.json": "c7c5bfc6f82d74e49ac746d187314ba7", + "build/assets/ba_data/data/languages/russian.json": "0fcc60bf1e8e19a74f02b0798728ec68", "build/assets/ba_data/data/languages/serbian.json": "d7452dd72ac0e51680cb39b5ebaa1c69", "build/assets/ba_data/data/languages/slovak.json": "3c08c748c96c71bd9e1d7291fb8817b6", - "build/assets/ba_data/data/languages/spanish.json": "4b262447f703eb4c6683b54af6b7b592", - "build/assets/ba_data/data/languages/swedish.json": "5142a96597d17d8344be96a603da64ac", - "build/assets/ba_data/data/languages/tamil.json": "5ececa2dde2bbe33ad61e580fa5b79ad", + "build/assets/ba_data/data/languages/spanish.json": "0a37387183a6634fc8e9ac225fcf20b1", + "build/assets/ba_data/data/languages/swedish.json": "039c803fad78f1018ad363d2a0be8582", + "build/assets/ba_data/data/languages/tamil.json": "ead39b864228696a9b0d19344bc4b5ec", "build/assets/ba_data/data/languages/thai.json": "1d665629361f302693dead39de8fa945", - "build/assets/ba_data/data/languages/turkish.json": "1c0a5c0c0c115107fb0752c92907f584", + "build/assets/ba_data/data/languages/turkish.json": "6153ca5248b8e4743e9501ac72378493", "build/assets/ba_data/data/languages/ukrainian.json": "23a98e5722d3e71e809a8a0063daa603", "build/assets/ba_data/data/languages/venetian.json": "a1315f5233ebbee1464683ac55d5d9d5", "build/assets/ba_data/data/languages/vietnamese.json": "5ae84265600b6cfda45c9bed18724e1d", @@ -4096,26 +4096,26 @@ "build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1", "build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae", "build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599", - "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "fa2f9a37401974a330f6406bfdde195a", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "ec0ca83cb8d63837d86024926a9f5792", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "22e11f5d894e02b521f1c77a3b1d14ad", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "803d4449de9e62bc33d62edaccb3a40c", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "5ee49f99993e6f690c955bf4e22ea232", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "f6882aef1cf0c4ab6a4d71b19e048ea3", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "2de6855febbe3fefbd1a696e54ff198c", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "76fff0d53458ff9308ee9050bfe42321", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "4b0f3502089e9a7ea6ea2db0c44ecee9", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "d426ae451363579868ed80e070ee1a7d", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "147e64e814f72846d5f78944df85f879", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "0e28cef28d1097cd61c1faa2f18b900d", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "213712de0e2e9c5fcbaf9b2cebd92ff7", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "34122e2302160ce65f4ac624e6b40876", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "09f8466080d70d84c15d697a659c6561", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "ad91f8448f3106a7d81f2615ab82d71c", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "6a369680967a22140b9a5d3dd65cfd65", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "eb2ccde783e4e7abaf40a76ed0be4a0c", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "112881e2d4429018dc5487a979d53a80", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "04b1f16241efd35e95ff544de09f3444", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "41a98f2ff00b086a13012b1d41b1b679", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "355efd9eb200adc050f8bf7280bf4ab7", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "99c968cdd2834d4ca0d8cfc1a5a45032", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "d6022d622fe97ca1f53ec82ab7760ba5", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "d940e7a52de205056f514dfb607ae7c2", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "70103854eb9efefbec06170eb180f0b2", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "bce00b851d23d89f79b4fddfdffc450b", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "cd129a1ee5f40d29885b151d7e03c1c9", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "49e4475f1042319638a1ac153179df29", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "82b1318e7502523952b53079298bc8f8", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "1db1588dcd7b6e0f363d136c560c6972", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "24df70b13ce76cb2e7e5a9764c5cbb60", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "5911060f6e9d00c5e2094808892e5498", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "bc46e5358dca0bbf898a3ddb653877e2", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "ceebd7928536a2168e13b2978cbe0f86", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "e42ef061ab1226560cfe85ff211cea73", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "d7aa5a88ad0b480429356b9d864f4cc4", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "ea44279e480430ce8bffbe5ea1c3ac9c", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "d4516c60d83688126ae0c525f5860e1c", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "36c639448372b428d361ad1b11b54754", "build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c", "build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "fa659b5d6119acba6570c92ce4d35ae2", "build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "73ad3303fe1a82005918fbc5dae3446c", @@ -4132,16 +4132,16 @@ "build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e", "build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "1659535e95e3047fda529543e265ac97", "build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "3e5c5fd0a09f55ba7b05ce1e2ec7171e", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "599167b1b452e9a060475c059ebb742e", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "4495e25c4e6e286ebe0ac547c3c785e5", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "ee961522b1a726d982df90d35178f4df", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "de121ab71098df1ff6a9b72b46c30401", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "6319a5f16af08ad8cd396472e623b4e1", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "1464b16e286fc6379aa6e9d8d7b7ddaa", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "64c3bce65d48d16c7b0f5f59105a8856", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "a10c2110bb0155790ddc49a44388ba4c", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "9b192a30bda69790d0b64f91f5e0994f", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "663e75e5c4ef1e7600508bba725c0bc1", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "468ba57dc9006630c0c3c65f660c45cf", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "59e48b3aaca43e98a74c2147a5235c78", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "8219f3131e89ff059d0524d6fbe76e73", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "24254f5fa2d8389a58a86c035a757254", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "cf0bd162dbb597c8f86739547f3cea79", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "85e3392a2b6a05f66eb43efc3045826b", "src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c", - "src/assets/ba_data/python/babase/_mgen/enums.py": "cb299985623bbcc86015cb103a424ae6", + "src/assets/ba_data/python/babase/_mgen/enums.py": "794d258d59fd17a61752843a9a0551ad", "src/ballistica/base/mgen/pyembed/binding_base.inc": "efa61468cf098f77cc6a234461d8b86d", "src/ballistica/base/mgen/pyembed/binding_base_app.inc": "97efb93f4bfd8e8b09f2db24398e29fc", "src/ballistica/classic/mgen/pyembed/binding_classic.inc": "3ceb412513963f0818ab39c58bf292e3", diff --git a/CHANGELOG.md b/CHANGELOG.md index 662d8848..bd00ec4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.37 (build 21986, api 9, 2024-09-04) +### 1.7.37 (build 22004, api 9, 2024-09-05) - Bumping api version to 9. As you'll see below, there's some UI changes that will require a bit of work for any UI mods to adapt to. If your mods don't touch UI stuff at all you can simply bump your api version and call it a day. @@ -36,6 +36,8 @@ was to add a higher level layer to the UI to make things like saving/restoring UI states easier, but I now plan to use `WindowState` classes to accomplish much of that in a more backward-compatible way. More on that below. +- Removed touch-specific button target-area adjustements. If you find any + buttons that are hard to hit accurately on a touchscreen, please holler. - Added a new `bauiv1.Window` subclass called `bauiv1.MainWindow` which handles what was previously called the 'main-menu-window' system which was a bit ad-hoc and messy. MainMenuWindows have a built-in stack system so things like @@ -80,6 +82,14 @@ - Removed `efro.util.enum_by_value()` which was a workaround for a Python bug that has been fixed for a few versions now. Instaed of `enum_by_value(MyEnumType, foo)` you can simply do `MyEnumType(foo)`. +- Removed `bauiv1.is_party_icon_visible()` as it is now always visible. +- 'ui_scale' is no longer available in _babase.env() since it can now change; + use `babase.get_ui_scale()` to get it now. +- Removed the UIScale control from the devtools window, which was only partially + wired up (it did not affect native layer bits). For now the official ways to + test UIScales are by using the UI panel in the dev-console or by setting the + `BA_UI_SCALE` env var. If we can get UIScale switches to feel seamless enough + at some point, it may be worth adding to display settings. ### 1.7.36 (build 21944, api 8, 2024-07-26) - Wired up Tokens, BombSquad's new purchasable currency. The first thing these diff --git a/config/requirements.txt b/config/requirements.txt index 42cf3454..96493d90 100644 --- a/config/requirements.txt +++ b/config/requirements.txt @@ -17,6 +17,6 @@ Sphinx==8.0.2 tomlkit==0.13.2 types-certifi==2021.10.8.3 types-filelock==3.2.7 -types-requests==2.32.0.20240712 +types-requests==2.32.0.20240905 typing_extensions==4.12.2 urllib3==2.2.2 diff --git a/src/assets/ba_data/python/babase/__init__.py b/src/assets/ba_data/python/babase/__init__.py index aca78d41..2bf58b84 100644 --- a/src/assets/ba_data/python/babase/__init__.py +++ b/src/assets/ba_data/python/babase/__init__.py @@ -56,6 +56,7 @@ from _babase import ( get_replays_dir, get_string_height, get_string_width, + get_ui_scale, get_v1_cloud_log_file_path, getsimplesound, has_user_run_commands, @@ -99,6 +100,7 @@ from _babase import ( set_low_level_config_value, set_thread_name, set_ui_input_device, + set_ui_scale, show_progress_bar, shutdown_suppress_begin, shutdown_suppress_end, @@ -254,8 +256,9 @@ __all__ = [ 'get_replays_dir', 'get_string_height', 'get_string_width', - 'get_v1_cloud_log_file_path', 'get_type_name', + 'get_ui_scale', + 'get_v1_cloud_log_file_path', 'getclass', 'getsimplesound', 'handle_leftover_v1_cloud_log_file', @@ -325,6 +328,7 @@ __all__ = [ 'set_low_level_config_value', 'set_thread_name', 'set_ui_input_device', + 'set_ui_scale', 'show_progress_bar', 'shutdown_suppress_begin', 'shutdown_suppress_end', diff --git a/src/assets/ba_data/python/babase/_app.py b/src/assets/ba_data/python/babase/_app.py index f852fbd6..164dbdb6 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -629,6 +629,29 @@ class App: self._initial_sign_in_completed = True self._update_state() + def set_ui_scale(self, scale: babase.UIScale) -> None: + """Change ui-scale on the fly. + + Currently this is mainly for debugging and will not + be called as part of normal app operation. + """ + assert _babase.in_logic_thread() + + # Apply to the native layer. + _babase.set_ui_scale(scale.name.lower()) + + # Inform all subsystems that something screen-related has + # changed. We assume subsystems won't be added at this point so + # we can use the list directly. + assert self._subsystem_registration_ended + for subsystem in self._subsystems: + try: + subsystem.on_screen_change() + except Exception: + logging.exception( + 'Error in on_screen_change() for subsystem %s.', subsystem + ) + def _set_intent(self, intent: AppIntent) -> None: from babase._appmode import AppMode @@ -718,7 +741,7 @@ class App: subsystem.reset() except Exception: logging.exception( - 'Error in reset for subsystem %s.', subsystem + 'Error in reset() for subsystem %s.', subsystem ) self._mode = mode @@ -805,7 +828,7 @@ class App: subsystem.on_app_loading() except Exception: logging.exception( - 'Error in on_app_loading for subsystem %s.', subsystem + 'Error in on_app_loading() for subsystem %s.', subsystem ) # Normally plus tells us when initial sign-in is done. If plus @@ -854,7 +877,7 @@ class App: subsystem.on_app_running() except Exception: logging.exception( - 'Error in on_app_running for subsystem %s.', subsystem + 'Error in on_app_running() for subsystem %s.', subsystem ) # Cut off new subsystem additions at this point. @@ -890,7 +913,8 @@ class App: subsystem.do_apply_app_config() except Exception: logging.exception( - 'Error in do_apply_app_config for subsystem %s.', subsystem + 'Error in do_apply_app_config() for subsystem %s.', + subsystem, ) # Let the native layer do its thing. @@ -1013,7 +1037,7 @@ class App: subsystem.on_app_suspend() except Exception: logging.exception( - 'Error in on_app_suspend for subsystem %s.', subsystem + 'Error in on_app_suspend() for subsystem %s.', subsystem ) def _on_unsuspend(self) -> None: @@ -1027,7 +1051,7 @@ class App: subsystem.on_app_unsuspend() except Exception: logging.exception( - 'Error in on_app_unsuspend for subsystem %s.', subsystem + 'Error in on_app_unsuspend() for subsystem %s.', subsystem ) def _on_shutting_down(self) -> None: @@ -1041,7 +1065,7 @@ class App: subsystem.on_app_shutdown() except Exception: logging.exception( - 'Error in on_app_shutdown for subsystem %s.', subsystem + 'Error in on_app_shutdown() for subsystem %s.', subsystem ) # Now kick off any async shutdown task(s). @@ -1059,7 +1083,7 @@ class App: subsystem.on_app_shutdown_complete() except Exception: logging.exception( - 'Error in on_app_shutdown_complete for subsystem %s.', + 'Error in on_app_shutdown_complete() for subsystem %s.', subsystem, ) diff --git a/src/assets/ba_data/python/babase/_appsubsystem.py b/src/assets/ba_data/python/babase/_appsubsystem.py index b1636af2..c22f40a8 100644 --- a/src/assets/ba_data/python/babase/_appsubsystem.py +++ b/src/assets/ba_data/python/babase/_appsubsystem.py @@ -8,7 +8,7 @@ from typing import TYPE_CHECKING import _babase if TYPE_CHECKING: - pass + from babase import UIScale class AppSubsystem: @@ -54,6 +54,9 @@ class AppSubsystem: def do_apply_app_config(self) -> None: """Called when the app config should be applied.""" + def on_screen_change(self) -> None: + """Called when screen dimensions or ui-scale changes.""" + def reset(self) -> None: """Reset the subsystem to a default state. diff --git a/src/assets/ba_data/python/babase/_devconsole.py b/src/assets/ba_data/python/babase/_devconsole.py index e4380f4e..b858fcc7 100644 --- a/src/assets/ba_data/python/babase/_devconsole.py +++ b/src/assets/ba_data/python/babase/_devconsole.py @@ -4,16 +4,17 @@ from __future__ import annotations import os -from typing import TYPE_CHECKING, override -from dataclasses import dataclass import logging +from functools import partial +from dataclasses import dataclass +from typing import TYPE_CHECKING, override import _babase if TYPE_CHECKING: from typing import Callable, Any, Literal - from babase import AppMode + from babase import AppMode, UIScale class DevConsoleTab: @@ -35,7 +36,7 @@ class DevConsoleTab: h_anchor: Literal['left', 'center', 'right'] = 'center', label_scale: float = 1.0, corner_radius: float = 8.0, - style: Literal['normal', 'dark'] = 'normal', + style: Literal['normal', 'light'] = 'normal', ) -> None: """Add a button to the tab being refreshed.""" assert _babase.app.devconsole.is_refreshing @@ -108,7 +109,6 @@ class DevConsoleTabAppModes(DevConsoleTab): @override def refresh(self) -> None: - from functools import partial modes = _babase.app.mode_selector.testable_app_modes() self.text( @@ -150,31 +150,43 @@ class DevConsoleTabUI(DevConsoleTab): @override def refresh(self) -> None: + from babase._mgen.enums import UIScale + # self.text( + # 'UI Testing', + # scale=0.8, + # pos=(15, 77), + # h_anchor='left', + # h_align='left', + # v_align='center', + # ) self.text( - 'UI Testing: Make sure all static UI fits in the' - ' virtual screen at all UI scales (not counting things' - ' that follow screen edges).', - scale=0.8, - pos=(15, 55), + 'Make sure all interactive UI fits in the' + ' virtual bounds at all UI-scales (not counting things' + ' that follow screen edges).\n' + 'Note that some elements may not reflect UI-scale changes' + ' until recreated.', + scale=0.6, + pos=(15, 70), h_anchor='left', h_align='left', - v_align='none', + v_align='center', ) ui_overlay = _babase.get_draw_ui_bounds() self.button( - 'Hide Virtual Screen' if ui_overlay else 'Show Virtual Screen', + 'Virtual Bounds ON' if ui_overlay else 'Virtual Bounds OFF', pos=(10, 10), size=(200, 30), h_anchor='left', label_scale=0.6, call=self.toggle_ui_overlay, + style='light' if ui_overlay else 'normal', ) - x = 320 + x = 300 self.text( - 'UI Scale:', - pos=(x - 10, 15), + 'UI-Scale', + pos=(x - 5, 15), h_anchor='left', h_align='right', v_align='none', @@ -182,16 +194,21 @@ class DevConsoleTabUI(DevConsoleTab): ) bwidth = 100 - for sz in ('small', 'medium', 'large'): + for scale in UIScale: self.button( - sz, + scale.name.capitalize(), pos=(x, 10), size=(bwidth, 30), h_anchor='left', label_scale=0.6, - call=lambda: _babase.screenmessage('UNDER CONSTRUCTION.'), + call=partial(_babase.app.set_ui_scale, scale), + style=( + 'light' + if scale.name.lower() == _babase.get_ui_scale() + else 'normal' + ), ) - x += bwidth + 10 + x += bwidth + 2 def toggle_ui_overlay(self) -> None: """Toggle UI overlay drawing.""" @@ -220,7 +237,7 @@ class DevConsoleTabTest(DevConsoleTab): size=(100, 30), h_anchor='left', label_scale=0.6, - style='dark', + style='light', ) self.text( 'TestText', diff --git a/src/assets/ba_data/python/baclassic/_appmode.py b/src/assets/ba_data/python/baclassic/_appmode.py index 1208b9e3..10f2fc65 100644 --- a/src/assets/ba_data/python/baclassic/_appmode.py +++ b/src/assets/ba_data/python/baclassic/_appmode.py @@ -49,6 +49,8 @@ class ClassicAppMode(AppMode): @override def on_activate(self) -> None: + print('CLASSIC ACTIVATING') + # Let the native layer do its thing. _baclassic.classic_app_mode_activate() @@ -108,6 +110,7 @@ class ClassicAppMode(AppMode): @override def on_deactivate(self) -> None: + print('CLASSIC DEACTIVATING') # Let the native layer do its thing. _baclassic.classic_app_mode_deactivate() diff --git a/src/assets/ba_data/python/baclassic/_appsubsystem.py b/src/assets/ba_data/python/baclassic/_appsubsystem.py index e10c5dfd..c09889cc 100644 --- a/src/assets/ba_data/python/baclassic/_appsubsystem.py +++ b/src/assets/ba_data/python/baclassic/_appsubsystem.py @@ -819,6 +819,8 @@ class ClassicAppSubsystem(babase.AppSubsystem): def invoke_main_menu_ui(self) -> None: """Bring up main menu ui.""" + print('INVOKING MAIN MENU UI') + # Bring up the last place we were, or start at the main menu otherwise. app = bauiv1.app env = app.env @@ -830,18 +832,15 @@ class ClassicAppSubsystem(babase.AppSubsystem): # UI stuff fails now in headless builds; avoid it. pass else: - # main_menu_location = ( - # bascenev1.app.ui_v1.get_main_menu_location() - # ) - # When coming back from a kiosk-mode game, jump to - # the kiosk start screen. + # When coming back from a kiosk-mode game, jump to the + # kiosk start screen. if env.demo or env.arcade: # pylint: disable=cyclic-import from bauiv1lib.kiosk import KioskWindow app.ui_v1.set_main_window( - KioskWindow(), from_window=False # Disable check here. + KioskWindow(), is_top_level=True, suppress_warning=True ) # ..or in normal cases go back to the main menu else: @@ -912,17 +911,3 @@ class ClassicAppSubsystem(babase.AppSubsystem): is_top_level=True, suppress_warning=True, ) - - # attempt to show any pending offers immediately. - # If that doesn't work, try again in a few seconds - # (we may not have heard back from the server) - # ..if that doesn't work they'll just have to wait - # until the next opportunity. - # if not specialoffer.show_offer(): - - # def try_again() -> None: - # if not specialoffer.show_offer(): - # # Try one last time.. - # bauiv1.apptimer(2.0, specialoffer.show_offer) - - # bauiv1.apptimer(2.0, try_again) diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index e2830cd1..b9de61fd 100644 --- a/src/assets/ba_data/python/baenv.py +++ b/src/assets/ba_data/python/baenv.py @@ -52,7 +52,7 @@ if TYPE_CHECKING: # Build number and version of the ballistica binary we expect to be # using. -TARGET_BALLISTICA_BUILD = 21986 +TARGET_BALLISTICA_BUILD = 22004 TARGET_BALLISTICA_VERSION = '1.7.37' diff --git a/src/assets/ba_data/python/bascenev1/_gameactivity.py b/src/assets/ba_data/python/bascenev1/_gameactivity.py index d990f818..fc9f0b83 100644 --- a/src/assets/ba_data/python/bascenev1/_gameactivity.py +++ b/src/assets/ba_data/python/bascenev1/_gameactivity.py @@ -64,44 +64,6 @@ class GameActivity(Activity[PlayerT, TeamT]): # (unless overridden by the map). default_music: bascenev1.MusicType | None = None - # @classmethod - # def create_settings_ui( - # cls, - # sessiontype: type[bascenev1.Session], - # settings: dict | None, - # completion_call: Callable[[dict | None], None], - # ) -> None: - # """Launch an in-game UI to configure settings for a game type. - - # 'sessiontype' should be the bascenev1.Session class the game will - # be used in. - - # 'settings' should be an existing settings dict (implies 'edit' - # ui mode) or None (implies 'add' ui mode). - - # 'completion_call' will be called with a filled-out settings dict on - # success or None on cancel. - - # Generally subclasses don't need to override this; if they override - # bascenev1.GameActivity.get_available_settings() and - # bascenev1.GameActivity.get_supported_maps() they can just rely on - # the default implementation here which calls those methods. - # """ - # # pylint: disable=cyclic-import - # from bauiv1lib.playlist.editgame import PlaylistEditGameWindow - - # assert babase.app.classic is not None - # babase.app.ui_v1.clear_main_window() - # babase.app.ui_v1.set_main_window( - # PlaylistEditGameWindow( - # cls, - # sessiontype, - # settings, - # completion_call=completion_call, - # ), - # from_window=False, # Disable check since we don't know. - # ) - @classmethod def getscoreconfig(cls) -> bascenev1.ScoreConfig: """Return info about game scoring setup; can be overridden by games.""" diff --git a/src/assets/ba_data/python/bauiv1/__init__.py b/src/assets/ba_data/python/bauiv1/__init__.py index 31b0de18..313b377b 100644 --- a/src/assets/ba_data/python/bauiv1/__init__.py +++ b/src/assets/ba_data/python/bauiv1/__init__.py @@ -111,7 +111,6 @@ from _bauiv1 import ( gettexture, hscrollwidget, imagewidget, - is_party_icon_visible, Mesh, rowwidget, scrollwidget, @@ -192,7 +191,6 @@ __all__ = [ 'in_main_menu', 'increment_analytics_count', 'is_browser_likely_available', - 'is_party_icon_visible', 'is_xcode_build', 'Keyboard', 'lock_all_input', diff --git a/src/assets/ba_data/python/bauiv1/_appsubsystem.py b/src/assets/ba_data/python/bauiv1/_appsubsystem.py index a5491755..e425f7fd 100644 --- a/src/assets/ba_data/python/bauiv1/_appsubsystem.py +++ b/src/assets/ba_data/python/bauiv1/_appsubsystem.py @@ -61,7 +61,6 @@ class UIV1AppSubsystem(babase.AppSubsystem): from bauiv1._uitypes import MainWindow super().__init__() - env = babase.env() # We hold only a weak ref to the current main Window; we want it # to be able to disappear on its own. That being said, we do @@ -72,18 +71,28 @@ class UIV1AppSubsystem(babase.AppSubsystem): self.quit_window: bauiv1.Widget | None = None - # The following should probably go away or move to classic. - # self._main_menu_location: str | None = None - # For storing arbitrary class-level state data for Windows or # other UI related classes. self.window_states: dict[type, Any] = {} - uiscalestr = babase.app.config.get('UI Scale', env['ui_scale']) - if uiscalestr == 'auto': - uiscalestr = env['ui_scale'] - self._uiscale: babase.UIScale + self._update_ui_scale() + + self.cleanupchecks: list[UICleanupCheck] = [] + self.upkeeptimer: babase.AppTimer | None = None + + self.title_color = (0.72, 0.7, 0.75) + self.heading_color = (0.72, 0.7, 0.75) + self.infotextcolor = (0.7, 0.9, 0.7) + + # Elements in our root UI will call anything here when + # activated. + self.root_ui_calls: dict[ + UIV1AppSubsystem.RootUIElement, Callable[[], None] + ] = {} + + def _update_ui_scale(self) -> None: + uiscalestr = babase.get_ui_scale() if uiscalestr == 'large': self._uiscale = babase.UIScale.LARGE elif uiscalestr == 'medium': @@ -94,18 +103,6 @@ class UIV1AppSubsystem(babase.AppSubsystem): logging.error("Invalid UIScale '%s'.", uiscalestr) self._uiscale = babase.UIScale.MEDIUM - self.cleanupchecks: list[UICleanupCheck] = [] - self.upkeeptimer: babase.AppTimer | None = None - - self.title_color = (0.72, 0.7, 0.75) - self.heading_color = (0.72, 0.7, 0.75) - self.infotextcolor = (0.7, 0.9, 0.7) - - # Elements in our root UI will call anything here when activated. - self.root_ui_calls: dict[ - UIV1AppSubsystem.RootUIElement, Callable[[], None] - ] = {} - @property def available(self) -> bool: """Can uiv1 currently be used? @@ -133,20 +130,20 @@ class UIV1AppSubsystem(babase.AppSubsystem): def on_app_loading(self) -> None: from bauiv1._uitypes import ui_upkeep - # IMPORTANT: If tweaking UI stuff, make sure it behaves for small, - # medium, and large UI modes. (doesn't run off screen, etc). - # The overrides below can be used to test with different sizes. - # Generally small is used on phones, medium is used on tablets/tvs, - # and large is on desktop computers or perhaps large tablets. When - # possible, run in windowed mode and resize the window to assure - # this holds true at all aspect ratios. + # IMPORTANT: If tweaking UI stuff, make sure it behaves for + # small, medium, and large UI modes. (doesn't run off screen, + # etc). The overrides below can be used to test with different + # sizes. Generally small is used on phones, medium is used on + # tablets/tvs, and large is on desktop computers or perhaps + # large tablets. When possible, run in windowed mode and resize + # the window to assure this holds true at all aspect ratios. - # UPDATE: A better way to test this is now by setting the environment - # variable BA_UI_SCALE to "small", "medium", or "large". - # This will affect system UIs not covered by the values below such - # as screen-messages. The below values remain functional, however, - # for cases such as Android where environment variables can't be set - # easily. + # UPDATE: A better way to test this is now by setting the + # environment variable BA_UI_SCALE to "small", "medium", or + # "large". This will affect system UIs not covered by the values + # below such as screen-messages. The below values remain + # functional, however, for cases such as Android where + # environment variables can't be set easily. if bool(False): # force-test ui scale self._uiscale = babase.UIScale.SMALL @@ -160,7 +157,9 @@ class UIV1AppSubsystem(babase.AppSubsystem): ) # Kick off our periodic UI upkeep. - # FIXME: Can probably kill this if we do immediate UI death checks. + + # FIXME: Can probably kill this if we do immediate UI death + # checks. self.upkeeptimer = babase.AppTimer(2.6543, ui_upkeep, repeat=True) def auto_set_back_window(self, from_window: MainWindow) -> None: @@ -181,11 +180,12 @@ class UIV1AppSubsystem(babase.AppSubsystem): f'Main window {main_window} provides no back-state;' f' cannot use auto-back.' ) - backwin = back_state.create_window(transition='in_left') - # Properly created state should have a value here. + # Valid states should have a value here. assert back_state.is_top_level is not None + backwin = back_state.create_window(transition='in_left') + self.set_main_window( backwin, from_window=from_window, @@ -213,7 +213,6 @@ class UIV1AppSubsystem(babase.AppSubsystem): MainWindow methods main_window_replace() and main_window_back() should be used when possible for navigation. """ - # pylint: disable=too-many-locals # pylint: disable=too-many-branches # pylint: disable=too-many-statements from bauiv1._uitypes import MainWindow @@ -275,8 +274,8 @@ class UIV1AppSubsystem(babase.AppSubsystem): try: if isinstance(from_window, bool): # For default val True we warn that the arg wasn't - # passed. False can be explicitly passed to disable this - # check. + # passed. False can be explicitly passed to disable + # this check. if from_window is True: caller_frame = inspect.stack()[1] caller_filename = caller_frame.filename @@ -289,8 +288,8 @@ class UIV1AppSubsystem(babase.AppSubsystem): caller_line_number, ) else: - # For everything else, warn if what they passed wasn't - # the previous main menu widget. + # For everything else, warn if what they passed + # wasn't the previous main menu widget. if from_window is not existing: caller_frame = inspect.stack()[1] caller_filename = caller_frame.filename @@ -344,12 +343,9 @@ class UIV1AppSubsystem(babase.AppSubsystem): ) window.main_window_back_state = None else: - oldwinstate = oldwin.get_main_window_state() - - # Store some common window stuff on its state. - oldwinstate.parent = oldwin.main_window_back_state - oldwinstate.is_top_level = oldwin.main_window_is_top_level - window.main_window_back_state = oldwinstate + window.main_window_back_state = self.save_main_window_state( + oldwin + ) self._main_window = window_weakref self._main_window_widget = window_widget @@ -376,3 +372,52 @@ class UIV1AppSubsystem(babase.AppSubsystem): self._main_window = empty_weakref(MainWindow) self._main_window_widget = None + + def save_main_window_state(self, window: MainWindow) -> MainWindowState: + """Fully initialize a window-state from a window. + + Use this to get a state for later restoration purposes. + Calling the window's get_main_window_state() directly is + insufficient. + """ + winstate = window.get_main_window_state() + + # Store some common window stuff on its state. + winstate.parent = window.main_window_back_state + winstate.is_top_level = window.main_window_is_top_level + + return winstate + + def restore_main_window_state(self, state: MainWindowState) -> None: + """Restore UI to a saved state.""" + existing = self.get_main_window() + if existing is not None: + raise RuntimeError('There is already a MainWindow.') + + # Valid states should have a value here. + assert state.is_top_level is not None + + win = state.create_window(transition=None) + self.set_main_window( + win, + from_window=False, # disable check + is_top_level=state.is_top_level, + back_state=state.parent, + suppress_warning=True, + ) + + @override + def on_screen_change(self) -> None: + # Update our stored UIScale. + self._update_ui_scale() + + # Update native bits (allow root widget to rebuild itself/etc.) + _bauiv1.on_screen_change() + + # Lastly, if we have a main window, recreate it to pick up the + # new UIScale/etc. + mainwindow = self.get_main_window() + if mainwindow is not None: + winstate = self.save_main_window_state(mainwindow) + self.clear_main_window(transition='instant') + self.restore_main_window_state(winstate) diff --git a/src/assets/ba_data/python/bauiv1/_uitypes.py b/src/assets/ba_data/python/bauiv1/_uitypes.py index b1aca134..00edc4cb 100644 --- a/src/assets/ba_data/python/bauiv1/_uitypes.py +++ b/src/assets/ba_data/python/bauiv1/_uitypes.py @@ -96,14 +96,20 @@ class MainWindow(Window): except Exception: logging.exception('Error in on_main_window_close() for %s.', self) - _bauiv1.containerwidget( - edit=self._root_widget, - transition=( - self._main_window_transition_out - if transition is None - else transition - ), - ) + # Note: normally transition of None means instant, but we use + # that to mean 'do the default' so we support a special + # 'instant' string.. + if transition == 'instant': + self._root_widget.delete() + else: + _bauiv1.containerwidget( + edit=self._root_widget, + transition=( + self._main_window_transition_out + if transition is None + else transition + ), + ) def main_window_has_control(self) -> bool: """Is this MainWindow allowed to change the global main window? diff --git a/src/assets/ba_data/python/bauiv1lib/coop/browser.py b/src/assets/ba_data/python/bauiv1lib/coop/browser.py index fa7fe785..7a04aeb7 100644 --- a/src/assets/ba_data/python/bauiv1lib/coop/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/coop/browser.py @@ -1022,64 +1022,6 @@ class CoopBrowserWindow(bui.MainWindow): def _enable_selectable_callback(self) -> None: self._do_selection_callbacks = True - # def _switch_to_league_rankings(self) -> None: - # # pylint: disable=cyclic-import - # from bauiv1lib.account import show_sign_in_prompt - # from bauiv1lib.league.rankwindow import LeagueRankWindow - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # plus = bui.app.plus - # assert plus is not None - - # if plus.get_v1_account_state() != 'signed_in': - # show_sign_in_prompt() - # return - # self._save_state() - # bui.containerwidget(edit=self._root_widget, transition='out_left') - # assert self._league_rank_button is not None - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # LeagueRankWindow( - # origin_widget=self._league_rank_button.get_button() - # ), - # from_window=self, - # ) - - # def _switch_to_score( - # self, - # show_tab: ( - # StoreBrowserWindow.TabID | None - # ) = StoreBrowserWindow.TabID.EXTRAS, - # ) -> None: - # # pylint: disable=cyclic-import - # from bauiv1lib.account import show_sign_in_prompt - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # plus = bui.app.plus - # assert plus is not None - - # if plus.get_v1_account_state() != 'signed_in': - # show_sign_in_prompt() - # return - # self._save_state() - # bui.containerwidget(edit=self._root_widget, transition='out_left') - # assert self._store_button is not None - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # StoreBrowserWindow( - # origin_widget=self._store_button.get_button(), - # show_tab=show_tab, - # back_location='CoopBrowserWindow', - # ), - # from_window=self, - # ) - def is_tourney_data_up_to_date(self) -> bool: """Return whether our tourney data is up to date.""" return self._tourney_data_up_to_date @@ -1233,24 +1175,6 @@ class CoopBrowserWindow(bui.MainWindow): position=tournament_button.button.get_screen_space_center(), ) - # def _back(self) -> None: - # # pylint: disable=cyclic-import - # from bauiv1lib.play import PlayWindow - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # # If something is selected, store it. - # self._save_state() - # bui.containerwidget( - # edit=self._root_widget, transition=self._transition_out - # ) - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # PlayWindow(transition='in_left'), from_window=self, is_back=True - # ) - def _save_state(self) -> None: cfg = bui.app.config try: diff --git a/src/assets/ba_data/python/bauiv1lib/fileselector.py b/src/assets/ba_data/python/bauiv1lib/fileselector.py index df17ad11..de92e6fb 100644 --- a/src/assets/ba_data/python/bauiv1lib/fileselector.py +++ b/src/assets/ba_data/python/bauiv1lib/fileselector.py @@ -33,8 +33,8 @@ class FileSelectorWindow(bui.MainWindow): valid_file_extensions = [] assert bui.app.classic is not None uiscale = bui.app.ui_v1.uiscale - self._width = 700 if uiscale is bui.UIScale.SMALL else 600 - self._x_inset = x_inset = 50 if uiscale is bui.UIScale.SMALL else 0 + self._width = 850 if uiscale is bui.UIScale.SMALL else 600 + self._x_inset = x_inset = 100 if uiscale is bui.UIScale.SMALL else 0 self._height = 365 if uiscale is bui.UIScale.SMALL else 418 self._callback = callback self._base_path = path @@ -54,7 +54,7 @@ class FileSelectorWindow(bui.MainWindow): root_widget=bui.containerwidget( size=(self._width, self._height), scale=( - 2.23 + 1.93 if uiscale is bui.UIScale.SMALL else 1.4 if uiscale is bui.UIScale.MEDIUM else 1.0 ), @@ -175,7 +175,6 @@ class FileSelectorWindow(bui.MainWindow): bui.getsound('error').play() def _on_folder_entry_activated(self) -> None: - bui.containerwidget(edit=self._root_widget, transition='out_right') if self._callback is not None: assert self._path is not None self._callback(self._path) @@ -204,9 +203,6 @@ class FileSelectorWindow(bui.MainWindow): elif os.path.isfile(test_path): if self._is_valid_file_path(test_path): bui.getsound('swish').play() - bui.containerwidget( - edit=self._root_widget, transition='out_right' - ) if self._callback is not None: self._callback(test_path) else: @@ -486,7 +482,6 @@ class FileSelectorWindow(bui.MainWindow): ) def _cancel(self) -> None: - # bui.containerwidget(edit=self._root_widget, transition='out_right') self.main_window_back() if self._callback is not None: self._callback(None) diff --git a/src/assets/ba_data/python/bauiv1lib/kiosk.py b/src/assets/ba_data/python/bauiv1lib/kiosk.py index 206569dc..c3814cd7 100644 --- a/src/assets/ba_data/python/bauiv1lib/kiosk.py +++ b/src/assets/ba_data/python/bauiv1lib/kiosk.py @@ -4,6 +4,8 @@ from __future__ import annotations +from typing import override + import bascenev1 as bs import bauiv1 as bui @@ -359,6 +361,20 @@ class KioskWindow(bui.MainWindow): 1.0, bui.WeakCall(self._update), repeat=True ) + @override + def get_main_window_state(self) -> bui.MainWindowState: + # Support recreating our window for back/refresh purposes. + cls = type(self) + return bui.BasicMainWindowState( + create_call=lambda transition, origin_widget: cls( + transition=transition, origin_widget=origin_widget + ) + ) + + @override + def on_main_window_close(self) -> None: + self._save_state() + def _restore_state(self) -> None: assert bui.app.classic is not None sel_name = bui.app.ui_v1.window_states.get(type(self)) @@ -510,13 +526,13 @@ class KioskWindow(bui.MainWindow): # pylint: disable=cyclic-import from bauiv1lib.mainmenu import MainMenuWindow - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return assert bui.app.classic is not None self._save_state() - bui.containerwidget(edit=self._root_widget, transition='out_left') bui.app.classic.did_menu_intro = True # prevent delayed transition-in - bui.app.ui_v1.set_main_window(MainMenuWindow(), from_window=self) + + self.main_window_replace(MainMenuWindow()) diff --git a/src/assets/ba_data/python/bauiv1lib/play.py b/src/assets/ba_data/python/bauiv1lib/play.py index 97ab6396..c52d27fb 100644 --- a/src/assets/ba_data/python/bauiv1lib/play.py +++ b/src/assets/ba_data/python/bauiv1lib/play.py @@ -44,7 +44,8 @@ class PlayWindow(bui.MainWindow): uiscale = bui.app.ui_v1.uiscale width = 1100 if uiscale is bui.UIScale.SMALL else 800 x_offs = 150 if uiscale is bui.UIScale.SMALL else 0 - height = 550 + y_offs = -60 if uiscale is bui.UIScale.SMALL else 0 + height = 650 if uiscale is bui.UIScale.SMALL else 550 button_width = 400 if origin_widget is not None: @@ -77,21 +78,34 @@ class PlayWindow(bui.MainWindow): transition=transition, origin_widget=origin_widget, ) - self._back_button = back_button = btn = bui.buttonwidget( - parent=self._root_widget, - position=(55 + x_offs, height - 132), - size=(120, 60), - scale=1.1, - text_res_scale=1.5, - text_scale=1.2, - autoselect=True, - label=bui.Lstr(resource='backText'), - button_type='back', - ) + + self._back_button: bui.Widget | None + if uiscale is bui.UIScale.SMALL: + self._back_button = None + bui.containerwidget( + edit=self._root_widget, + on_cancel_call=self.main_window_back, + ) + else: + self._back_button = bui.buttonwidget( + parent=self._root_widget, + position=(55 + x_offs, height - 132 + y_offs), + size=(60, 60), + scale=1.1, + text_res_scale=1.5, + text_scale=1.2, + autoselect=True, + label=bui.charstr(bui.SpecialChar.BACK), + button_type='backSmall', + on_activate_call=self.main_window_back, + ) + bui.containerwidget( + edit=self._root_widget, cancel_button=self._back_button + ) txt = bui.textwidget( parent=self._root_widget, - position=(width * 0.5, height - 101), + position=(width * 0.5, height - 101 + y_offs), # position=(width * 0.5, height - # (101 if main_menu else 61)), size=(0, 0), @@ -110,16 +124,14 @@ class PlayWindow(bui.MainWindow): v_align='center', ) - bui.buttonwidget( - edit=btn, - button_type='backSmall', - size=(60, 60), - label=bui.charstr(bui.SpecialChar.BACK), - ) if uiscale is bui.UIScale.SMALL: bui.textwidget(edit=txt, text='') - v = height - (110 if self._playlist_select_context is None else 90) + v = ( + height + - (110 if self._playlist_select_context is None else 90) + + y_offs + ) v -= 100 clr = (0.6, 0.7, 0.6, 1.0) v -= 280 if self._playlist_select_context is None else 180 @@ -510,11 +522,8 @@ class PlayWindow(bui.MainWindow): ) if uiscale is bui.UIScale.SMALL: - back_button.delete() bui.containerwidget( edit=self._root_widget, - on_cancel_call=self.main_window_back, - # cancel_button=bui.get_special_widget('back_button'), selected_child=( self._coop_button if self._playlist_select_context is None @@ -522,12 +531,8 @@ class PlayWindow(bui.MainWindow): ), ) else: - bui.buttonwidget( - edit=back_button, on_activate_call=self.main_window_back - ) bui.containerwidget( edit=self._root_widget, - cancel_button=back_button, selected_child=( self._coop_button if self._playlist_select_context is None @@ -763,7 +768,7 @@ class PlayWindow(bui.MainWindow): sel = self._coop_button elif sel_name == 'Free-for-All Games': sel = self._free_for_all_button - elif sel_name == 'Back': + elif sel_name == 'Back' and self._back_button is not None: sel = self._back_button else: sel = ( diff --git a/src/assets/ba_data/python/bauiv1lib/playlist/browser.py b/src/assets/ba_data/python/bauiv1lib/playlist/browser.py index 7523639d..65721765 100644 --- a/src/assets/ba_data/python/bauiv1lib/playlist/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/playlist/browser.py @@ -716,26 +716,23 @@ class PlaylistBrowserWindow(bui.MainWindow): PlaylistCustomizeBrowserWindow, ) - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return - self._save_state() - bui.containerwidget(edit=self._root_widget, transition='out_left') - bui.app.ui_v1.set_main_window( + self.main_window_replace( PlaylistCustomizeBrowserWindow( origin_widget=self._customize_button, sessiontype=self._sessiontype, - ), - from_window=self, + ) ) def _on_back_press(self) -> None: # pylint: disable=cyclic-import # from bauiv1lib.play import PlayWindow - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return # Store our selected playlist if that's changed. diff --git a/src/assets/ba_data/python/bauiv1lib/playlist/editgame.py b/src/assets/ba_data/python/bauiv1lib/playlist/editgame.py index 9192703f..22a10fda 100644 --- a/src/assets/ba_data/python/bauiv1lib/playlist/editgame.py +++ b/src/assets/ba_data/python/bauiv1lib/playlist/editgame.py @@ -545,10 +545,6 @@ class PlaylistEditGameWindow(bui.MainWindow): if not self.main_window_has_control(): return - # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - self._config = self._getconfig() # Replace ourself with the map-select UI. @@ -556,26 +552,12 @@ class PlaylistEditGameWindow(bui.MainWindow): PlaylistMapSelectWindow( self._gametype, self._sessiontype, - # copy.deepcopy(self._getconfig()), self._config, self._edit_info, self._completion_call, ) ) - # bui.containerwidget(edit=self._root_widget, transition='out_left') - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # PlaylistMapSelectWindow( - # self._gametype, - # self._sessiontype, - # copy.deepcopy(self._getconfig()), - # self._edit_info, - # self._completion_call, - # ), - # from_window=self, - # ) - def _choice_inc( self, setting_name: str, diff --git a/src/assets/ba_data/python/bauiv1lib/playlist/mapselect.py b/src/assets/ba_data/python/bauiv1lib/playlist/mapselect.py index 6383945d..c58128dc 100644 --- a/src/assets/ba_data/python/bauiv1lib/playlist/mapselect.py +++ b/src/assets/ba_data/python/bauiv1lib/playlist/mapselect.py @@ -61,7 +61,6 @@ class PlaylistMapSelectWindow(bui.MainWindow): super().__init__( root_widget=bui.containerwidget( size=(width, height + top_extra), - # transition=transition, scale=( 1.95 if uiscale is bui.UIScale.SMALL @@ -299,66 +298,22 @@ class PlaylistMapSelectWindow(bui.MainWindow): self.main_window_replace( StoreBrowserWindow( - # modal=True, show_tab=StoreBrowserWindow.TabID.MAPS, - # on_close_call=self._on_store_close, origin_widget=self._get_more_maps_button, minimal_toolbars=True, ) ) - # def _on_store_close(self) -> None: - # pass - # self._refresh(select_get_more_maps_button=True) - def _select(self, map_name: str) -> None: - # from bauiv1lib.playlist.editgame import PlaylistEditGameWindow # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + if not self.main_window_has_control(): return self._config['settings']['map'] = map_name self.main_window_back() - # bui.containerwidget(edit=self._root_widget, transition='out_right') - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # PlaylistEditGameWindow( - # self._gametype, - # self._sessiontype, - # self._config, - # self._completion_call, - # default_selection='map', - # transition='in_left', - # edit_info=self._edit_info, - # ), - # from_window=self, - # ) def _select_with_delay(self, map_name: str) -> None: bui.lock_all_input() bui.apptimer(0.1, bui.unlock_all_input) bui.apptimer(0.1, bui.WeakCall(self._select, map_name)) - - # def _cancel(self) -> None: - # from bauiv1lib.playlist.editgame import PlaylistEditGameWindow - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # bui.containerwidget(edit=self._root_widget, transition='out_right') - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # PlaylistEditGameWindow( - # self._gametype, - # self._sessiontype, - # self._config, - # self._completion_call, - # default_selection='map', - # transition='in_left', - # edit_info=self._edit_info, - # ), - # from_window=self, - # is_back=True, - # ) diff --git a/src/assets/ba_data/python/bauiv1lib/playoptions.py b/src/assets/ba_data/python/bauiv1lib/playoptions.py index 0428db3a..0c772183 100644 --- a/src/assets/ba_data/python/bauiv1lib/playoptions.py +++ b/src/assets/ba_data/python/bauiv1lib/playoptions.py @@ -500,8 +500,8 @@ class PlayOptionsWindow(PopupWindow): cfg = bui.app.config cfg[self._pvars.config_name + ' Playlist Selection'] = self._playlist - # Head back to the gather window in playlist-select mode - # or start the game in regular mode. + # Head back to the gather window in playlist-select mode or + # start the game in regular mode. if self._playlist_select_context is not None: # from bauiv1lib.gather import GatherWindow @@ -514,14 +514,6 @@ class PlayOptionsWindow(PopupWindow): cfg['Private Party Host Session Type'] = typename bui.getsound('gunCocking').play() - # assert bui.app.classic is not None - # # Note: this is a wonky situation where we aren't actually - # # the main window but we set it on behalf of the main window - # # that popped us up. - # bui.app.ui_v1.set_main_window( - # GatherWindow(transition='in_right'), - # from_window=False, # Disable this test. - # ) self._transition_out(transition='out_left') if self._delegate is not None: self._delegate.on_play_options_window_run_game() diff --git a/src/assets/ba_data/python/bauiv1lib/profile/browser.py b/src/assets/ba_data/python/bauiv1lib/profile/browser.py index 5cc6ad19..f743dd3d 100644 --- a/src/assets/ba_data/python/bauiv1lib/profile/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/profile/browser.py @@ -268,13 +268,6 @@ class ProfileBrowserWindow(bui.MainWindow): self.main_window_replace(EditProfileWindow(existing_profile=None)) - # self._save_state() - # bui.containerwidget(edit=self._root_widget, transition='out_left') - # bui.app.ui_v1.set_main_window( - # EditProfileWindow(existing_profile=None), - # from_window=self if self._in_main_menu else False, - # ) - def _delete_profile(self) -> None: # pylint: disable=cyclic-import from bauiv1lib import confirm diff --git a/src/assets/ba_data/python/bauiv1lib/profile/edit.py b/src/assets/ba_data/python/bauiv1lib/profile/edit.py index e2bc1660..4bf5be4d 100644 --- a/src/assets/ba_data/python/bauiv1lib/profile/edit.py +++ b/src/assets/ba_data/python/bauiv1lib/profile/edit.py @@ -19,19 +19,16 @@ class EditProfileWindow(bui.MainWindow, CharacterPickerDelegate): def reload_window(self) -> None: """Transitions out and recreates ourself.""" - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return - bui.screenmessage('UNDER CONSTRUCTION') - return - # bui.containerwidget(edit=self._root_widget, transition='out_left') - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # EditProfileWindow(self.getname()), - # from_window=self, - # is_back=True, - # ) + # Replace ourself with ourself, but keep the same back location. + assert self.main_window_back_state is not None + self.main_window_replace( + EditProfileWindow(self.getname()), + back_state=self.main_window_back_state, + ) def __init__( self, @@ -548,6 +545,15 @@ class EditProfileWindow(bui.MainWindow, CharacterPickerDelegate): from bauiv1lib import account from bauiv1lib.profile import upgrade as pupgrade + new_name = self.getname().strip() + + if self._existing_profile and self._existing_profile != new_name: + bui.screenmessage( + 'Unsaved changes found; you must save first.', color=(1, 0, 0) + ) + bui.getsound('error').play() + return + plus = bui.app.plus assert plus is not None diff --git a/src/assets/ba_data/python/bauiv1lib/settings/devtools.py b/src/assets/ba_data/python/bauiv1lib/settings/devtools.py index 4c97422a..80d924ca 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/devtools.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/devtools.py @@ -40,7 +40,7 @@ class DevToolsWindow(bui.MainWindow): self._scroll_width = self._width - (100 + 2 * x_inset) self._scroll_height = self._height - 115.0 self._sub_width = self._scroll_width * 0.95 - self._sub_height = 350.0 + self._sub_height = 300.0 super().__init__( root_widget=bui.containerwidget( @@ -169,37 +169,41 @@ class DevToolsWindow(bui.MainWindow): ), ) - v -= self._spacing * 2.5 - bui.textwidget( - parent=self._subcontainer, - position=(170, v + 10), - size=(0, 0), - text=bui.Lstr(resource='uiScaleText'), - color=app.ui_v1.title_color, - h_align='center', - v_align='center', - ) + # Currently this is not wired up. The current official way to test + # UIScales is either to use the switcher in the dev-console or to + # set the BA_UI_SCALE env var. + if bool(False): + v -= self._spacing * 2.5 + bui.textwidget( + parent=self._subcontainer, + position=(170, v + 10), + size=(0, 0), + text=bui.Lstr(resource='uiScaleText'), + color=app.ui_v1.title_color, + h_align='center', + v_align='center', + ) - PopupMenu( - parent=self._subcontainer, - position=(230, v - 20), - button_size=(200.0, 60.0), - width=100.0, - choices=[ - 'auto', - 'small', - 'medium', - 'large', - ], - choices_display=[ - bui.Lstr(resource='autoText'), - bui.Lstr(resource='sizeSmallText'), - bui.Lstr(resource='sizeMediumText'), - bui.Lstr(resource='sizeLargeText'), - ], - current_choice=app.config.get('UI Scale', 'auto'), - on_value_change_call=self._set_uiscale, - ) + PopupMenu( + parent=self._subcontainer, + position=(230, v - 20), + button_size=(200.0, 60.0), + width=100.0, + choices=[ + 'auto', + 'small', + 'medium', + 'large', + ], + choices_display=[ + bui.Lstr(resource='autoText'), + bui.Lstr(resource='sizeSmallText'), + bui.Lstr(resource='sizeMediumText'), + bui.Lstr(resource='sizeLargeText'), + ], + current_choice=app.config.get('UI Scale', 'auto'), + on_value_change_call=self._set_uiscale, + ) @override def get_main_window_state(self) -> bui.MainWindowState: diff --git a/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py b/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py index 962eb3ad..94b266d1 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/gamepad.py @@ -798,22 +798,15 @@ class GamepadSettingsWindow(bui.MainWindow): def _cancel(self) -> None: - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: - return - if self._modal: + # no-op if our underlying widget is dead or on its way out. + if not self._root_widget or self._root_widget.transitioning_out: + return bui.containerwidget( edit=self._root_widget, transition=self._transition_out ) else: self.main_window_back() - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # ControlsSettingsWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) def _reset(self) -> None: from bauiv1lib.confirm import ConfirmWindow diff --git a/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py b/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py index 3226f7ae..5d2f6f96 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/keyboard.py @@ -377,17 +377,16 @@ class ConfigKeyboardWindow(bui.MainWindow): """Called when the popup is closing.""" def _save(self) -> None: - # from bauiv1lib.settings.controls import ControlsSettingsWindow - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return assert bui.app.classic is not None - # bui.containerwidget(edit=self._root_widget, transition='out_right') bui.getsound('gunCocking').play() - # There's a chance the device disappeared; handle that gracefully. + # There's a chance the device disappeared; handle that + # gracefully. if not self._input: return @@ -402,8 +401,8 @@ class ConfigKeyboardWindow(bui.MainWindow): if val != -1: dst2[key] = val - # Send this config to the master-server so we can generate - # more defaults in the future. + # Send this config to the master-server so we can generate more + # defaults in the future. if bui.app.classic is not None: bui.app.classic.master_server_v1_post( 'controllerConfig', @@ -418,11 +417,6 @@ class ConfigKeyboardWindow(bui.MainWindow): bui.app.config.apply_and_commit() self.main_window_back() - # bui.app.ui_v1.set_main_window( - # ControlsSettingsWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) class AwaitKeyboardInputWindow(bui.Window): diff --git a/src/assets/ba_data/python/bauiv1lib/settings/nettesting.py b/src/assets/ba_data/python/bauiv1lib/settings/nettesting.py index 9542c07f..23a6142f 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/nettesting.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/nettesting.py @@ -56,10 +56,11 @@ class NetTestingWindow(bui.MainWindow): self._done_button: bui.Widget | None = bui.buttonwidget( parent=self._root_widget, position=(46, self._height - 77), - size=(120, 60), - scale=0.8, + size=(60, 60), + scale=0.9, + label=bui.charstr(bui.SpecialChar.BACK), + button_type='backSmall', autoselect=True, - label=bui.Lstr(resource='doneText'), on_activate_call=self.main_window_back, ) @@ -164,28 +165,11 @@ class NetTestingWindow(bui.MainWindow): def _show_val_testing(self) -> None: assert bui.app.classic is not None - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return - bui.app.ui_v1.set_main_window(NetValTestingWindow(), from_window=self) - bui.containerwidget(edit=self._root_widget, transition='out_left') - - # def _done(self) -> None: - # # pylint: disable=cyclic-import - # from bauiv1lib.settings.advanced import AdvancedSettingsWindow - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # AdvancedSettingsWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) - # bui.containerwidget(edit=self._root_widget, transition='out_right') + self.main_window_replace(NetValTestingWindow()) def _run_diagnostics(weakwin: weakref.ref[NetTestingWindow]) -> None: diff --git a/src/assets/ba_data/python/bauiv1lib/settings/touchscreen.py b/src/assets/ba_data/python/bauiv1lib/settings/touchscreen.py index ad8195a7..e468f0c2 100644 --- a/src/assets/ba_data/python/bauiv1lib/settings/touchscreen.py +++ b/src/assets/ba_data/python/bauiv1lib/settings/touchscreen.py @@ -22,7 +22,6 @@ class TouchscreenSettingsWindow(bui.MainWindow): ) -> None: self._width = 780 self._height = 380 - # self._spacing = 40 self._r = 'configTouchscreenWindow' bs.set_touchscreen_editing(True) @@ -302,19 +301,3 @@ class TouchscreenSettingsWindow(bui.MainWindow): del cfg[cfgkey] cfg.apply_and_commit() bui.apptimer(0, self._build_gui) - - # def _back(self) -> None: - # from bauiv1lib.settings import controls - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # bui.containerwidget(edit=self._root_widget, transition='out_right') - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # controls.ControlsSettingsWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) - # bs.set_touchscreen_editing(False) diff --git a/src/assets/ba_data/python/bauiv1lib/soundtrack/browser.py b/src/assets/ba_data/python/bauiv1lib/soundtrack/browser.py index a052b075..315ee998 100644 --- a/src/assets/ba_data/python/bauiv1lib/soundtrack/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/soundtrack/browser.py @@ -15,9 +15,6 @@ if TYPE_CHECKING: REQUIRE_PRO = False -# Temp. -UNDER_CONSTRUCTION = True - class SoundtrackBrowserWindow(bui.MainWindow): """Window for browsing soundtracks.""" @@ -397,25 +394,6 @@ class SoundtrackBrowserWindow(bui.MainWindow): music.music_types[bui.app.classic.MusicPlayMode.REGULAR] ) - # def _back(self) -> None: - # # pylint: disable=cyclic-import - # from bauiv1lib.settings.audio import AudioSettingsWindow - - # # no-op if our underlying widget is dead or on its way out. - # if not self._root_widget or self._root_widget.transitioning_out: - # return - - # self._save_state() - # bui.containerwidget( - # edit=self._root_widget, transition=self._transition_out - # ) - # assert bui.app.classic is not None - # bui.app.ui_v1.set_main_window( - # AudioSettingsWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) - def _edit_soundtrack_with_sound(self) -> None: # pylint: disable=cyclic-import from bauiv1lib.purchase import PurchaseWindow @@ -434,12 +412,8 @@ class SoundtrackBrowserWindow(bui.MainWindow): from bauiv1lib.purchase import PurchaseWindow from bauiv1lib.soundtrack.edit import SoundtrackEditWindow - if UNDER_CONSTRUCTION: - bui.screenmessage('UNDER CONSTRUCTION') - return - - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we don't have control. + if not self.main_window_has_control(): return if REQUIRE_PRO and ( @@ -448,8 +422,10 @@ class SoundtrackBrowserWindow(bui.MainWindow): ): PurchaseWindow(items=['pro']) return + if self._selected_soundtrack is None: return + if self._selected_soundtrack == '__default__': bui.getsound('error').play() bui.screenmessage( @@ -458,12 +434,8 @@ class SoundtrackBrowserWindow(bui.MainWindow): ) return - self._save_state() - bui.containerwidget(edit=self._root_widget, transition='out_left') - assert bui.app.classic is not None - bui.app.ui_v1.set_main_window( - SoundtrackEditWindow(existing_soundtrack=self._selected_soundtrack), - from_window=self, + self.main_window_replace( + SoundtrackEditWindow(existing_soundtrack=self._selected_soundtrack) ) def _get_soundtrack_display_name(self, soundtrack: str) -> bui.Lstr: @@ -554,8 +526,8 @@ class SoundtrackBrowserWindow(bui.MainWindow): from bauiv1lib.purchase import PurchaseWindow from bauiv1lib.soundtrack.edit import SoundtrackEditWindow - if UNDER_CONSTRUCTION: - bui.screenmessage('UNDER CONSTRUCTION') + # no-op if we're not in control. + if not self.main_window_has_control(): return if REQUIRE_PRO and ( @@ -564,11 +536,8 @@ class SoundtrackBrowserWindow(bui.MainWindow): ): PurchaseWindow(items=['pro']) return - self._save_state() - bui.containerwidget(edit=self._root_widget, transition='out_left') - bui.app.ui_v1.set_main_window( - SoundtrackEditWindow(existing_soundtrack=None), from_window=self - ) + + self.main_window_replace(SoundtrackEditWindow(existing_soundtrack=None)) def _create_done(self, new_soundtrack: str) -> None: if new_soundtrack is not None: diff --git a/src/assets/ba_data/python/bauiv1lib/soundtrack/edit.py b/src/assets/ba_data/python/bauiv1lib/soundtrack/edit.py index 5d7132ad..27fb5c1b 100644 --- a/src/assets/ba_data/python/bauiv1lib/soundtrack/edit.py +++ b/src/assets/ba_data/python/bauiv1lib/soundtrack/edit.py @@ -26,8 +26,6 @@ class SoundtrackEditWindow(bui.MainWindow): ): # pylint: disable=too-many-statements - print('SPAWNING EDIT') - appconfig = bui.app.config self._r = 'editSoundtrackWindow' self._folder_tex = bui.gettexture('folder') @@ -110,7 +108,7 @@ class SoundtrackEditWindow(bui.MainWindow): self._existing_soundtrack_name = existing_soundtrack self._last_edited_song_type = None else: - # otherwise they can pass info on an in-progress edit + # Otherwise they can pass info on an in-progress edit. self._soundtrack = existing_soundtrack['soundtrack'] self._soundtrack_name = existing_soundtrack['name'] self._existing_soundtrack_name = existing_soundtrack[ @@ -202,7 +200,13 @@ class SoundtrackEditWindow(bui.MainWindow): # Pull this out of self here; if we do it in the lambda we'll # keep our window alive due to the 'self' reference. - existing_soundtrack = self._existing_soundtrack + existing_soundtrack = { + 'name': self._soundtrack_name, + 'existing_name': self._existing_soundtrack_name, + 'soundtrack': self._soundtrack, + 'last_edited_song_type': self._last_edited_song_type, + } + return bui.BasicMainWindowState( create_call=lambda transition, origin_widget: cls( transition=transition, @@ -348,8 +352,6 @@ class SoundtrackEditWindow(bui.MainWindow): assert bui.app.classic is not None music = bui.app.classic.music - print('GoT RESTORE', state, musictype, entry) - # Apply the change and recreate the window. soundtrack = state['soundtrack'] existing_entry = ( @@ -370,14 +372,20 @@ class SoundtrackEditWindow(bui.MainWindow): else: soundtrack[musictype] = entry + mainwindow = bui.app.ui_v1.get_main_window() + assert mainwindow is not None + + mainwindow.main_window_back_state = state['back_state'] + mainwindow.main_window_back() + def _get_entry( self, song_type: str, entry: Any, selection_target_name: str ) -> None: assert bui.app.classic is not None music = bui.app.classic.music - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return if selection_target_name != '': @@ -388,22 +396,17 @@ class SoundtrackEditWindow(bui.MainWindow): 'soundtrack': self._soundtrack, 'last_edited_song_type': song_type, } - self.main_window_replace( - music.get_music_player().select_entry( - bui.Call(self._restore_editor, state, song_type), - entry, - selection_target_name, - ) + new_win = music.get_music_player().select_entry( + bui.Call(self._restore_editor, state, song_type), + entry, + selection_target_name, ) - # bui.containerwidget(edit=self._root_widget, transition='out_left') - # bui.app.ui_v1.set_main_window( - # music.get_music_player().select_entry( - # bui.Call(self._restore_editor, state, song_type), - # entry, - # selection_target_name, - # ), - # from_window=self, - # ) + self.main_window_replace(new_win) + + # Once we've set the new window, grab the back-state; we'll use + # that to jump back here after selection completes. + assert new_win.main_window_back_state is not None + state['back_state'] = new_win.main_window_back_state def _test(self, song_type: bs.MusicType) -> None: assert bui.app.classic is not None @@ -460,15 +463,8 @@ class SoundtrackEditWindow(bui.MainWindow): music.set_music_play_mode(bui.app.classic.MusicPlayMode.REGULAR) self.main_window_back() - # bui.containerwidget(edit=self._root_widget, transition='out_right') - # bui.app.ui_v1.set_main_window( - # SoundtrackBrowserWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) def _do_it(self) -> None: - # from bauiv1lib.soundtrack.browser import SoundtrackBrowserWindow # no-op if our underlying widget is dead or on its way out. if not self._root_widget or self._root_widget.transitioning_out: @@ -514,7 +510,6 @@ class SoundtrackEditWindow(bui.MainWindow): cfg.commit() bui.getsound('gunCocking').play() - # bui.containerwidget(edit=self._root_widget, transition='out_right') # Resets music back to normal. music.set_music_play_mode( @@ -522,11 +517,6 @@ class SoundtrackEditWindow(bui.MainWindow): ) self.main_window_back() - # bui.app.ui_v1.set_main_window( - # SoundtrackBrowserWindow(transition='in_left'), - # from_window=self, - # is_back=True, - # ) def _do_it_with_sound(self) -> None: bui.getsound('swish').play() diff --git a/src/assets/ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py b/src/assets/ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py index 31879986..64ae95c0 100644 --- a/src/assets/ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py +++ b/src/assets/ba_data/python/bauiv1lib/soundtrack/entrytypeselect.py @@ -189,12 +189,10 @@ class SoundtrackEntryTypeSelectWindow(bui.MainWindow): MacMusicAppPlaylistSelectWindow, ) - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return - # bui.containerwidget(edit=self._root_widget, transition='out_left') - current_playlist_entry: str | None if ( music.get_soundtrack_entry_type(self._current_entry) @@ -211,22 +209,16 @@ class SoundtrackEntryTypeSelectWindow(bui.MainWindow): self._callback, current_playlist_entry, self._current_entry ) ) - # MacMusicAppPlaylistSelectWindow( - # self._callback, current_playlist_entry, self._current_entry - # ), - # from_window=self, - # ) def _on_music_file_press(self) -> None: from babase import android_get_external_files_dir from baclassic.osmusic import OSMusicPlayer from bauiv1lib.fileselector import FileSelectorWindow - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return - # bui.containerwidget(edit=self._root_widget, transition='out_left') base_path = android_get_external_files_dir() assert bui.app.classic is not None @@ -241,28 +233,15 @@ class SoundtrackEntryTypeSelectWindow(bui.MainWindow): allow_folders=False, ), ) - # bui.app.ui_v1.set_main_window( - # FileSelectorWindow( - # base_path, - # callback=self._music_file_selector_cb, - # show_base_path=False, - # valid_file_extensions=( - # OSMusicPlayer.get_valid_music_file_extensions() - # ), - # allow_folders=False, - # ), - # from_window=self, - # ) def _on_music_folder_press(self) -> None: from bauiv1lib.fileselector import FileSelectorWindow from babase import android_get_external_files_dir - # no-op if our underlying widget is dead or on its way out. - if not self._root_widget or self._root_widget.transitioning_out: + # no-op if we're not in control. + if not self.main_window_has_control(): return - # bui.containerwidget(edit=self._root_widget, transition='out_left') base_path = android_get_external_files_dir() assert bui.app.classic is not None @@ -275,16 +254,6 @@ class SoundtrackEntryTypeSelectWindow(bui.MainWindow): allow_folders=True, ), ) - # bui.app.ui_v1.set_main_window( - # FileSelectorWindow( - # base_path, - # callback=self._music_folder_selector_cb, - # show_base_path=False, - # valid_file_extensions=[], - # allow_folders=True, - # ), - # from_window=self, - # ) def _music_file_selector_cb(self, result: str | None) -> None: if result is None: @@ -300,10 +269,8 @@ class SoundtrackEntryTypeSelectWindow(bui.MainWindow): def _on_default_press(self) -> None: self.main_window_back() - # bui.containerwidget(edit=self._root_widget, transition='out_right') self._callback(None) def _on_cancel_press(self) -> None: self.main_window_back() - # bui.containerwidget(edit=self._root_widget, transition='out_right') self._callback(self._current_entry) diff --git a/src/assets/ba_data/python/bauiv1lib/store/browser.py b/src/assets/ba_data/python/bauiv1lib/store/browser.py index 17a36740..44771ac8 100644 --- a/src/assets/ba_data/python/bauiv1lib/store/browser.py +++ b/src/assets/ba_data/python/bauiv1lib/store/browser.py @@ -42,10 +42,7 @@ class StoreBrowserWindow(bui.MainWindow): self, transition: str | None = 'in_right', origin_widget: bui.Widget | None = None, - # modal: bool = False, show_tab: StoreBrowserWindow.TabID | None = None, - # on_close_call: Callable[[], Any] | None = None, - # back_location: str | None = None, minimal_toolbars: bool = False, ): # pylint: disable=too-many-statements @@ -59,20 +56,11 @@ class StoreBrowserWindow(bui.MainWindow): bui.set_analytics_screen('Store Window') - # Need to store this ourself for modal mode. - # if origin_widget is not None: - # self._transition_out = 'out_scale' - # else: - # self._transition_out = 'out_right' - self.button_infos: dict[str, dict[str, Any]] | None = None self.update_buttons_timer: bui.AppTimer | None = None self._status_textwidget_update_timer = None - # self._back_location = back_location - # self._on_close_call = on_close_call self._show_tab = show_tab - # self._modal = modal self._width = 1670 if uiscale is bui.UIScale.SMALL else 1040 self._x_inset = x_inset = 310 if uiscale is bui.UIScale.SMALL else 0 self._height = ( @@ -1252,31 +1240,13 @@ class StoreBrowserWindow(bui.MainWindow): except Exception: logging.exception('Error restoring state for %s.', self) - # def _back(self) -> None: - - # # if self._modal: - # # # no-op if our underlying widget is dead or on its way out. - # # if not self._root_widget or self._root_widget.transitioning_out: - # # return - # # self._save_state() - # # bui.containerwidget( - # # edit=self._root_widget, transition=self._transition_out - # # ) - # # else: - # # no-op if we're not currently in control. - # if not self.main_window_has_control(): - # return - # self.main_window_back() - # # if self._on_close_call is not None: - # # self._on_close_call() - def _check_merch_availability_in_bg_thread() -> None: # pylint: disable=cell-var-from-loop - # Merch is available from some countries only. - # Make a reasonable check to ask the master-server about this at - # launch and store the results. + # Merch is available from some countries only. Make a reasonable + # check to ask the master-server about this at launch and store the + # results. plus = bui.app.plus assert plus is not None diff --git a/src/assets/ba_data/python/bauiv1lib/watch.py b/src/assets/ba_data/python/bauiv1lib/watch.py index 7d6ced1a..2db96a78 100644 --- a/src/assets/ba_data/python/bauiv1lib/watch.py +++ b/src/assets/ba_data/python/bauiv1lib/watch.py @@ -87,19 +87,13 @@ class WatchWindow(bui.MainWindow): parent=self._root_widget, autoselect=True, position=(70 + x_inset, self._height - 74), - size=(140, 60), + size=(60, 60), scale=1.1, - label=bui.Lstr(resource='backText'), - button_type='back', + label=bui.charstr(bui.SpecialChar.BACK), + button_type='backSmall', on_activate_call=self.main_window_back, ) bui.containerwidget(edit=self._root_widget, cancel_button=btn) - bui.buttonwidget( - edit=btn, - button_type='backSmall', - size=(60, 60), - label=bui.charstr(bui.SpecialChar.BACK), - ) bui.textwidget( parent=self._root_widget, @@ -368,7 +362,7 @@ class WatchWindow(bui.MainWindow): bui.fade_screen(True) assert self._my_replay_selected is not None bs.new_replay_session( - bui.get_replays_dir() + '/' + self._my_replay_selected + f'{bui.get_replays_dir()}/{self._my_replay_selected}' ) except Exception: logging.exception('Error running replay session.') diff --git a/src/ballistica/base/app_mode/empty_app_mode.cc b/src/ballistica/base/app_mode/empty_app_mode.cc index 2cd147a1..34138439 100644 --- a/src/ballistica/base/app_mode/empty_app_mode.cc +++ b/src/ballistica/base/app_mode/empty_app_mode.cc @@ -3,6 +3,7 @@ #include "ballistica/base/app_mode/empty_app_mode.h" #include "ballistica/base/graphics/component/simple_component.h" +#include "ballistica/base/graphics/text/text_group.h" namespace ballistica::base { diff --git a/src/ballistica/base/base.cc b/src/ballistica/base/base.cc index 6266558e..b9063780 100644 --- a/src/ballistica/base/base.cc +++ b/src/ballistica/base/base.cc @@ -4,10 +4,12 @@ #include "ballistica/base/app_adapter/app_adapter.h" #include "ballistica/base/app_mode/empty_app_mode.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/assets/assets_server.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/audio/audio_server.h" #include "ballistica/base/dynamics/bg/bg_dynamics_server.h" +#include "ballistica/base/graphics/graphics.h" #include "ballistica/base/graphics/graphics_server.h" #include "ballistica/base/graphics/support/screen_messages.h" #include "ballistica/base/graphics/text/text_graphics.h" @@ -24,7 +26,6 @@ #include "ballistica/base/support/huffman.h" #include "ballistica/base/support/plus_soft.h" #include "ballistica/base/support/stdio_console.h" -#include "ballistica/base/ui/dev_console.h" #include "ballistica/base/ui/ui_delegate.h" #include "ballistica/core/python/core_python.h" #include "ballistica/shared/foundation/event_loop.h" @@ -193,12 +194,6 @@ void BaseFeatureSet::OnAssetsAvailable() { } void BaseFeatureSet::StartApp() { - // { - // // TEST - recreate the ID python dumps in its thread tracebacks. - // auto val = PyThread_get_thread_ident(); - // printf("MAIN THREAD IS %#018lx\n", val); - // } - BA_PRECONDITION(g_core->InMainThread()); BA_PRECONDITION(g_base); @@ -987,4 +982,14 @@ void BaseFeatureSet::Reset() { audio->Reset(); } +void BaseFeatureSet::SetUIScale(UIScale scale) { + assert(InLogicThread()); + + // Store the canonical value in UI. + ui->SetScale(scale); + + // Let interested parties know that it has changed. + graphics->OnUIScaleChange(); +} + } // namespace ballistica::base diff --git a/src/ballistica/base/base.h b/src/ballistica/base/base.h index 8c0c76c4..711b8462 100644 --- a/src/ballistica/base/base.h +++ b/src/ballistica/base/base.h @@ -5,7 +5,6 @@ #include #include -#include #include #include "ballistica/core/support/base_soft.h" @@ -781,6 +780,9 @@ class BaseFeatureSet : public FeatureSetNativeComponent, /// unsupported. void ClipboardSetText(const std::string& text); + /// Set overall ui scale for the app. + void SetUIScale(UIScale scale); + // Const subsystems. AppAdapter* const app_adapter; AppConfig* const app_config; diff --git a/src/ballistica/base/dynamics/collision_cache.cc b/src/ballistica/base/dynamics/collision_cache.cc index 5f26c1fb..4d3ae725 100644 --- a/src/ballistica/base/dynamics/collision_cache.cc +++ b/src/ballistica/base/dynamics/collision_cache.cc @@ -2,6 +2,7 @@ #include "ballistica/base/dynamics/collision_cache.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ode/ode_collision_kernel.h" #include "ode/ode_collision_space_internal.h" diff --git a/src/ballistica/base/graphics/component/object_component.cc b/src/ballistica/base/graphics/component/object_component.cc index 89d3fda7..7030abef 100644 --- a/src/ballistica/base/graphics/component/object_component.cc +++ b/src/ballistica/base/graphics/component/object_component.cc @@ -2,6 +2,8 @@ #include "ballistica/base/graphics/component/object_component.h" +#include "ballistica/base/assets/assets.h" + namespace ballistica::base { void ObjectComponent::WriteConfig() { diff --git a/src/ballistica/base/graphics/component/render_component.cc b/src/ballistica/base/graphics/component/render_component.cc index c10083a7..2e0198f3 100644 --- a/src/ballistica/base/graphics/component/render_component.cc +++ b/src/ballistica/base/graphics/component/render_component.cc @@ -2,6 +2,8 @@ #include "ballistica/base/graphics/component/render_component.h" +#include "ballistica/shared/math/rect.h" + namespace ballistica::base { void RenderComponent::ScissorPush(const Rect& rect) { diff --git a/src/ballistica/base/graphics/component/render_component.h b/src/ballistica/base/graphics/component/render_component.h index b0cc1b5e..9184a9fe 100644 --- a/src/ballistica/base/graphics/component/render_component.h +++ b/src/ballistica/base/graphics/component/render_component.h @@ -5,7 +5,12 @@ #include -#include "ballistica/base/graphics/renderer/renderer.h" +#include "ballistica/base/assets/mesh_asset.h" +#include "ballistica/base/graphics/graphics.h" +#include "ballistica/base/graphics/renderer/render_pass.h" +#include "ballistica/base/graphics/support/frame_def.h" +#include "ballistica/base/graphics/support/render_command_buffer.h" +#include "ballistica/shared/math/rect.h" namespace ballistica::base { diff --git a/src/ballistica/base/graphics/component/simple_component.cc b/src/ballistica/base/graphics/component/simple_component.cc index 6075dc19..e99f438c 100644 --- a/src/ballistica/base/graphics/component/simple_component.cc +++ b/src/ballistica/base/graphics/component/simple_component.cc @@ -2,6 +2,8 @@ #include "ballistica/base/graphics/component/simple_component.h" +#include "ballistica/base/assets/assets.h" + namespace ballistica::base { void SimpleComponent::WriteConfig() { diff --git a/src/ballistica/base/graphics/component/smoke_component.cc b/src/ballistica/base/graphics/component/smoke_component.cc index eaebe8d1..3a849189 100644 --- a/src/ballistica/base/graphics/component/smoke_component.cc +++ b/src/ballistica/base/graphics/component/smoke_component.cc @@ -2,6 +2,8 @@ #include "ballistica/base/graphics/component/smoke_component.h" +#include "ballistica/base/assets/assets.h" + namespace ballistica::base { void SmokeComponent::WriteConfig() { diff --git a/src/ballistica/base/graphics/component/sprite_component.cc b/src/ballistica/base/graphics/component/sprite_component.cc index 2c9d01fc..b653bb26 100644 --- a/src/ballistica/base/graphics/component/sprite_component.cc +++ b/src/ballistica/base/graphics/component/sprite_component.cc @@ -2,6 +2,8 @@ #include "ballistica/base/graphics/component/sprite_component.h" +#include "ballistica/base/assets/assets.h" + namespace ballistica::base { void SpriteComponent::WriteConfig() { diff --git a/src/ballistica/base/graphics/gl/renderer_gl.cc b/src/ballistica/base/graphics/gl/renderer_gl.cc index 38f8b173..bfb5582a 100644 --- a/src/ballistica/base/graphics/gl/renderer_gl.cc +++ b/src/ballistica/base/graphics/gl/renderer_gl.cc @@ -25,7 +25,7 @@ #include "ballistica/base/graphics/gl/program/program_sprite_gl.h" #include "ballistica/base/graphics/gl/render_target_gl.h" #include "ballistica/base/graphics/gl/texture_data_gl.h" -#include "ballistica/base/platform/base_platform.h" +#include "ballistica/shared/math/rect.h" // Turn this off to see how much blend overdraw is occurring. #define BA_GL_ENABLE_BLEND 1 @@ -254,42 +254,6 @@ void RendererGL::CheckGLCapabilities_() { // On Android, look at the GL version and try to get gl3 funcs to // determine if we're running ES3 or not. #if BA_OSTYPE_ANDROID - // bool have_es3; - // #if BA_USE_ES3_INCLUDES - // have_es3 = true; - // #else - // have_es3 = (strstr(version_str, "OpenGL ES 3.") && gl3stubInit()); - // #endif // BA_OSTYPE_ANDROID - - // if (have_es3) { - // g_running_es3 = true; - // } else { - // #if !BA_USE_ES3_INCLUDES - // g_running_es3 = false; - - // // Can still support some stuff like framebuffer-blit with es2 - // extensions. assert(glBlitFramebuffer == nullptr || - // !first_extension_check_); glBlitFramebuffer = - // (decltype(glBlitFramebuffer))eglGetProcAddress("glBlitFramebufferNV"); - // assert(glRenderbufferStorageMultisample == nullptr - // || !first_extension_check_); - // glRenderbufferStorageMultisample = - // (decltype(glRenderbufferStorageMultisample))eglGetProcAddress( - // "glRenderbufferStorageMultisampleNV"); - - // assert(glGenVertexArrays == nullptr || !first_extension_check_); - // glGenVertexArrays = - // (decltype(glGenVertexArrays))eglGetProcAddress("glGenVertexArraysOES"); - // assert(glDeleteVertexArrays == nullptr || !first_extension_check_); - // glDeleteVertexArrays = - // (decltype(glDeleteVertexArrays))eglGetProcAddress( - // "glDeleteVertexArraysOES"); - // assert(glBindVertexArray == nullptr || !first_extension_check_); - // glBindVertexArray = - // (decltype(glBindVertexArray))eglGetProcAddress("glBindVertexArrayOES"); - - // #endif // BA_USE_ES3_INCLUDES - // } BA_DEBUG_CHECK_GL_ERROR; @@ -300,75 +264,7 @@ void RendererGL::CheckGLCapabilities_() { assert(gl_version_major() == 3); is_speedy_android_device_ = gl_version_minor() >= 2; - // is_extra_speedy_android_device_ = false; is_adreno_ = (strstr(renderer, "Adreno") != nullptr); - // draws_shields_funny_ = false; // Start optimistic. - - // Ali tv box. - // if (!strcmp(renderer, "Mali-450 MP")) { - // is_speedy_android_device_ = true; // this is borderline - // speedy/extra-speedy - // // draws_shields_funny_ = true; - // } - - // Firetv, etc.. lets enable MSAA. - // if (!strcmp(renderer, "Adreno (TM) 320")) { - // is_recent_adreno_ = true; - // } - - // This is right on the borderline, but lets go with extra-speedy I guess. - // if (!strcmp(renderer, "Adreno (TM) 330")) { - // is_recent_adreno_ = true; - // is_extra_speedy_android_device_ = true; - // } - - // *any* of the 4xx or 5xx series are extra-speedy. - // if (strstr(renderer, "Adreno (TM) 4") || strstr(renderer, "Adreno (TM) 5") - // || strstr(renderer, "Adreno (TM) 6")) { - // is_extra_speedy_android_device_ = true; - // is_recent_adreno_ = true; - // } - - // Some speedy malis (Galaxy S6 / Galaxy S7-ish). - // if (strstr(renderer, "Mali-T760") || strstr(renderer, "Mali-T860") - // || strstr(renderer, "Mali-T880")) { - // is_extra_speedy_android_device_ = true; - // } - - // Note 8 is speed-tastic - // if (!strcmp(renderer, "Mali-G71") || !strcmp(renderer, "Mali-G72")) { - // is_extra_speedy_android_device_ = true; - // } - - // Covers Nexus player. - // HMM Scratch that - this winds up being too slow for phones using this chip. - // if (strstr(renderer, "PowerVR Rogue G6430")) { - // is_extra_speedy_android_device_ = true; - // } - - // Figure out if we're a Tegra 4/K1/etc since we do some special stuff on - // those... - // if (!strcmp(renderer, "NVIDIA Tegra")) { - // // tegra 4 won't have ES3 but will have framebuffer_multisample - // if (!g_running_es3 && CheckGLExtension(ex, "framebuffer_multisample")) { - // is_tegra_4_ = true; - // is_speedy_android_device_ = true; - // } else if (g_running_es3) { - // // running ES3 - must be a K1 (for now) - // is_tegra_k1_ = true; - // is_extra_speedy_android_device_ = true; - // } else { - // // looks like Tegra-2 era stuff was just "NVIDIA Tegra" as well... - // } - // } - - // Also store this globally for a few other bits of the app to use.. - // g_core->platform->set_is_tegra_k1(is_tegra_k1_); - - // Extra-speedy implies speedy too.. - // if (is_extra_speedy_android_device_) { - // is_speedy_android_device_ = true; - // } #endif // BA_OSTYPE_ANDROID @@ -407,15 +303,11 @@ void RendererGL::CheckGLCapabilities_() { g_base->graphics_server->SetTextureCompressionTypes(c_types); - // Both GL 3 and GL ES 3.0 support depth textures (and thus our high - // quality mode) as a core feature. - // g_base->graphics->SetSupportsHighQualityGraphics(true); - // Store the tex-compression type we support. BA_DEBUG_CHECK_GL_ERROR; - // Anisotropic sampling is still an extension as of both GL 3 and ES 3, - // so we need to test for it. + // Anisotropic sampling is still an extension as of both GL 3 and ES 3, so + // we need to test for it. anisotropic_support_ = CheckGLExtension(extensions, "texture_filter_anisotropic"); if (anisotropic_support_) { @@ -436,8 +328,8 @@ void RendererGL::CheckGLCapabilities_() { combined_texture_image_unit_count_ = GLGetInt(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS); - // If we're running ES3, ask about our max multisample counts and whether we - // can enable MSAA. + // If we're running ES3, ask about our max multisample counts and whether + // we can enable MSAA. msaa_max_samples_rgb565_ = msaa_max_samples_rgb8_ = 0; // start pessimistic bool have_gl_get_internal_format_iv{}; @@ -850,12 +742,6 @@ void RendererGL::SyncGLState_() { glFrontFace(GL_CCW); } BA_DEBUG_CHECK_GL_ERROR; - - // if (time(nullptr)%2 == 0) { - // glEnable(GL_FRAMEBUFFER_SRGB); - // } else { - // glDisable(GL_FRAMEBUFFER_SRGB); - // } #endif // BA_RIFT_BUILD active_tex_unit_ = -1; // force a set next time @@ -948,8 +834,8 @@ void RendererGL::SyncGLState_() { assert(VAR&& VAR == dynamic_cast(buffer->Get())); \ buffer++ -// Takes all latest mesh data from the client side and applies it -// to our gl implementations. +// Takes all latest mesh data from the client side and applies it to our gl +// implementations. void RendererGL::UpdateMeshes( const std::vector >& meshes, const std::vector& index_sizes, @@ -1193,7 +1079,8 @@ void RendererGL::ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, const TextureAsset* t = buffer->GetTexture(); const TextureAsset* t_mask = buffer->GetTexture(); p->SetColorTexture(t); - // If this isn't a full-res texture, ramp down the blurring we do. + // If this isn't a full-res texture, ramp down the blurring we + // do. p->SetShadow(shadow_offset_x, shadow_offset_y, std::max(0.0f, shadow_blur), shadow_opacity); p->SetMaskUV2Texture(t_mask); @@ -1215,7 +1102,8 @@ void RendererGL::ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, const TextureAsset* t = buffer->GetTexture(); const TextureAsset* t_mask = buffer->GetTexture(); p->SetColorTexture(t); - // If this isn't a full-res texture, ramp down the blurring we do. + // If this isn't a full-res texture, ramp down the blurring we + // do. p->SetShadow(shadow_offset_x, shadow_offset_y, std::max(0.0f, shadow_blur), shadow_opacity); p->SetMaskUV2Texture(t_mask); @@ -1612,7 +1500,7 @@ void RendererGL::ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, buffer->GetFloats(&r, &g, &b, &reflect_r, &reflect_g, &reflect_b); ProgramObjectGL* p; - // Testing why reflection is wonky.. + // Testing why reflection is wonky. if (explicit_bool(false)) { p = world_space ? obj_lightshad_worldspace_prog_ : obj_lightshad_prog_; @@ -1928,8 +1816,8 @@ void RendererGL::ProcessRenderCommandBuffer(RenderCommandBuffer* buffer, case ShadingType::kSpecial: { SetDoubleSided_(false); - // if we ever need to use non-blend version - // of this in real renders, we should split off a non-blend version + // If we ever need to use non-blend version of this in real + // renders, we should split off a non-blend version. SetBlend(true); SetBlendPremult(true); auto source = (SpecialComponent::Source)buffer->GetInt(); @@ -2211,8 +2099,8 @@ void RendererGL::BlitBuffer(RenderTarget* src_in, RenderTarget* dst_in, bool do_shader_blit{true}; - // If they want depth we *MUST* use glBlitFramebuffer and can't have linear - // interp. + // If they want depth we *MUST* use glBlitFramebuffer and can't have + // linear interp. if (depth) { assert(!force_shader_mode); linear_interpolation = false; @@ -2250,7 +2138,7 @@ void RendererGL::BlitBuffer(RenderTarget* src_in, RenderTarget* dst_in, g_base->graphics_server->ModelViewReset(); g_base->graphics_server->SetOrthoProjection(-1, 1, -1, 1, -1, 1); - // Copied from ShadingType::kSimpleColor + // Copied from ShadingType::kSimpleColor. SetDoubleSided_(false); SetBlend(false); ProgramSimpleGL* p = simple_tex_prog_; @@ -2554,14 +2442,6 @@ auto RendererGL::GetFunkyDepthIssue_() -> bool { return funky_depth_issue_; } -// auto RendererGL::GetDrawsShieldsFunny_() -> bool { -// if (!draws_shields_funny_set_) { -// BA_LOG_ONCE(LogLevel::kError, -// "fetching draws-shields-funny value but not set"); -// } -// return draws_shields_funny_; -// } - #if BA_OSTYPE_ANDROID std::string RendererGL::GetAutoAndroidRes() { assert(g_base->app_adapter->InGraphicsContext()); @@ -2759,9 +2639,9 @@ void RendererGL::Load() { p = shield_prog_ = new ProgramShieldGL(this, 0); RetainShader_(p); - // Conditional seems to be a *very* slight win on some architectures (A7), a - // loss on some (A5) and a wash on some (Adreno 320). - // Gonna wait before a clean win before turning it on. + // Conditional seems to be a *very* slight win on some architectures (A7), + // a loss on some (A5) and a wash on some (Adreno 320). Gonna wait before + // a clean win before turning it on. p = postprocess_prog_ = new ProgramPostProcessGL(this, high_qual_pp_flag); RetainShader_(p); if (g_base->graphics_server->quality() >= GraphicsQuality::kHigher) { @@ -2805,8 +2685,8 @@ void RendererGL::Load() { UpdateVignetteTex_(true); } - // Let's pre-fill our recyclable mesh-datas list to reduce the need to make - // more which could cause hitches. + // Let's pre-fill our recyclable mesh-datas list to reduce the need to + // make more which could cause hitches. assert(recycle_mesh_datas_simple_split_.empty()); for (int i = 0; i < 10; i++) { recycle_mesh_datas_simple_split_.push_back(new MeshDataSimpleSplitGL(this)); @@ -2958,7 +2838,7 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, switch (mesh_type) { case MeshDataType::kIndexedSimpleSplit: { MeshDataSimpleSplitGL* data; - // use a recycled one if we've got one.. otherwise create a new one + // Use a recycled one if we've got one; otherwise create a new one. auto i = recycle_mesh_datas_simple_split_.rbegin(); if (i != recycle_mesh_datas_simple_split_.rend()) { data = *i; @@ -2971,7 +2851,7 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, } case MeshDataType::kIndexedObjectSplit: { MeshDataObjectSplitGL* data; - // use a recycled one if we've got one.. otherwise create a new one + // Use a recycled one if we've got one; otherwise create a new one. auto i = recycle_mesh_datas_object_split_.rbegin(); if (i != recycle_mesh_datas_object_split_.rend()) { data = *i; @@ -2984,7 +2864,7 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, } case MeshDataType::kIndexedSimpleFull: { MeshDataSimpleFullGL* data; - // use a recycled one if we've got one.. otherwise create a new one + // Use a recycled one if we've got one; otherwise create a new one. auto i = recycle_mesh_datas_simple_full_.rbegin(); if (i != recycle_mesh_datas_simple_full_.rend()) { data = *i; @@ -2998,7 +2878,7 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, } case MeshDataType::kIndexedDualTextureFull: { MeshDataDualTextureFullGL* data; - // use a recycled one if we've got one.. otherwise create a new one + // Use a recycled one if we've got one; otherwise create a new one. auto i = recycle_mesh_datas_dual_texture_full_.rbegin(); if (i != recycle_mesh_datas_dual_texture_full_.rend()) { data = *i; @@ -3012,7 +2892,7 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, } case MeshDataType::kIndexedSmokeFull: { MeshDataSmokeFullGL* data; - // use a recycled one if we've got one.. otherwise create a new one + // Use a recycled one if we've got one; otherwise create a new one. auto i = recycle_mesh_datas_smoke_full_.rbegin(); if (i != recycle_mesh_datas_smoke_full_.rend()) { data = *i; @@ -3026,7 +2906,7 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, } case MeshDataType::kSprite: { MeshDataSpriteGL* data; - // use a recycled one if we've got one.. otherwise create a new one + // Use a recycled one if we've got one; otherwise create a new one. auto i = recycle_mesh_datas_sprite_.rbegin(); if (i != recycle_mesh_datas_sprite_.rend()) { data = *i; @@ -3046,10 +2926,9 @@ auto RendererGL::NewMeshData(MeshDataType mesh_type, void RendererGL::DeleteMeshData(MeshRendererData* source_in, MeshDataType mesh_type) { - // When we're done with mesh-data we keep it around for recycling. - // It seems that killing off VAO/VBOs can be hitchy (on mac at least). - // Hmmm should we have some sort of threshold at which point we kill off - // some? + // When we're done with mesh-data we keep it around for recycling. It + // seems that killing off VAO/VBOs can be hitchy (on mac at least). Hmmm + // should we have some sort of threshold at which point we kill off some? switch (mesh_type) { case MeshDataType::kIndexedSimpleSplit: { @@ -3105,8 +2984,8 @@ void RendererGL::DeleteMeshData(MeshRendererData* source_in, } void RendererGL::CheckForErrors() { - // lets only check periodically.. i doubt it hurts to run this all the time - // but just in case... + // Lets only check periodically. I doubt it hurts to run this all the time + // but just in case. error_check_counter_++; if (error_check_counter_ > 120) { error_check_counter_ = 0; @@ -3201,8 +3080,8 @@ void RendererGL::GenerateCameraBufferBlurPasses() { true, // linear_interp false, // depth true, // tex - false, // depthTex - high_quality_fbos, // highQuality + false, // depth_tex + high_quality_fbos, // high_quality false, // msaa false // alpha )); // NOLINT(whitespace/parens) @@ -3215,8 +3094,8 @@ void RendererGL::GenerateCameraBufferBlurPasses() { true, // linear_interp false, // depth true, // tex - false, // depthTex - false, // highQuality + false, // depth_tex + false, // high_quality false, // msaa false // alpha )); // NOLINT(whitespace/parens) @@ -3263,9 +3142,9 @@ void RendererGL::CardboardEnableScissor() { glEnable(GL_SCISSOR_TEST); } void RendererGL::VREyeRenderBegin() { assert(g_core->vr_mode()); - // On rift we need to turn off srgb conversion for each eye render - // so we can dump our linear data into oculus' srgb buffer as-is. - // (we really should add proper srgb support to the engine at some point) + // On rift we need to turn off srgb conversion for each eye render so we + // can dump our linear data into oculus' srgb buffer as-is. (we really + // should add proper srgb support to the engine at some point). #if BA_RIFT_BUILD glDisable(GL_FRAMEBUFFER_SRGB); #endif // BA_RIFT_BUILD @@ -3275,7 +3154,7 @@ void RendererGL::VREyeRenderBegin() { #if BA_VR_BUILD void RendererGL::VRSyncRenderStates() { - // GL state has been mucked with outside of our code; let's resync stuff.. + // GL state has been mucked with outside of our code; let's resync stuff. SyncGLState_(); } #endif // BA_VR_BUILD diff --git a/src/ballistica/base/graphics/gl/renderer_gl.h b/src/ballistica/base/graphics/gl/renderer_gl.h index 383bd356..c747f9d1 100644 --- a/src/ballistica/base/graphics/gl/renderer_gl.h +++ b/src/ballistica/base/graphics/gl/renderer_gl.h @@ -7,8 +7,6 @@ #include #include -#include "ballistica/shared/ballistica.h" - #if BA_ENABLE_OPENGL #include "ballistica/base/graphics/gl/gl_sys.h" @@ -27,13 +25,6 @@ namespace ballistica::base { -// extern int g_msaa_max_samples_rgb565; -// extern int g_msaa_max_samples_rgb8; -// extern bool g_vao_support; -// extern bool g_running_es3; -// extern bool g_anisotropic_support; -// extern float g_max_anisotropy; - // For now lets not go above 8 since that's what the iPhone 3gs has. ...haha // perhaps can reconsider that since the 3gs was 15 years ago. constexpr int kMaxGLTexUnitsUsed = 5; @@ -227,7 +218,6 @@ class RendererGL : public Renderer { private: static auto GetFunkyDepthIssue_() -> bool; - // static auto GetDrawsShieldsFunny_()->bool; void CheckFunkyDepthIssue_(); auto GetMSAASamplesForFramebuffer_(int width, int height) -> int; void UpdateMSAAEnabled_() override; @@ -248,8 +238,8 @@ class RendererGL : public Renderer { void ScissorPop_(RenderTarget* render_target); void BindVertexArray_(GLuint v); - // Note: This is only for use when VAOs aren't supported. - // void SetVertexAttributeArrayEnabled_(GLuint i, bool enabled); + // Note: This is only for use when VAOs aren't supported. void + // SetVertexAttributeArrayEnabled_(GLuint i, bool enabled); void BindTexture_(GLuint type, const TextureAsset* t, GLuint tex_unit = 0); void BindTexture_(GLuint type, GLuint tex, GLuint tex_unit = 0); void BindTextureUnit(uint32_t tex_unit); @@ -276,8 +266,6 @@ class RendererGL : public Renderer { bool double_sided_{}; bool invalidate_framebuffer_support_{}; bool checked_gl_version_{}; - GLint gl_version_major_{}; - GLint gl_version_minor_{}; int last_blur_res_count_{}; float last_cam_buffer_width_{}; float last_cam_buffer_height_{}; @@ -289,13 +277,15 @@ class RendererGL : public Renderer { float vignette_tex_inner_b_{}; float depth_range_min_{}; float depth_range_max_{}; + GLint gl_version_major_{}; + GLint gl_version_minor_{}; GLint screen_framebuffer_{}; GLuint random_tex_{}; - GLuint vignette_tex_{}; GLint viewport_x_{}; GLint viewport_y_{}; GLint viewport_width_{}; GLint viewport_height_{}; + GLuint vignette_tex_{}; millisecs_t dof_update_time_{}; std::vector > blur_buffers_; std::vector > shaders_; diff --git a/src/ballistica/base/graphics/graphics.cc b/src/ballistica/base/graphics/graphics.cc index 772a0497..0ca9a658 100644 --- a/src/ballistica/base/graphics/graphics.cc +++ b/src/ballistica/base/graphics/graphics.cc @@ -11,6 +11,8 @@ #include "ballistica/base/graphics/component/special_component.h" #include "ballistica/base/graphics/component/sprite_component.h" #include "ballistica/base/graphics/graphics_server.h" +#include "ballistica/base/graphics/mesh/image_mesh.h" +#include "ballistica/base/graphics/renderer/renderer.h" #include "ballistica/base/graphics/support/camera.h" #include "ballistica/base/graphics/support/net_graph.h" #include "ballistica/base/graphics/support/screen_messages.h" @@ -1535,12 +1537,23 @@ void Graphics::SetScreenResolution(float x, float y) { return; } - // We'll need to ship a new settings to the server with this change. - graphics_settings_dirty_ = true; - res_x_ = x; res_y_ = y; + UpdateScreen_(); +} + +void Graphics::OnUIScaleChange() { + // UIScale affects our virtual res calculations. Redo those. + UpdateScreen_(); +} + +void Graphics::UpdateScreen_() { + assert(g_base->InLogicThread()); + + // We'll need to ship a new settings to the server with this change. + graphics_settings_dirty_ = true; + // Calc virtual res. In vr mode our virtual res is independent of our // screen size (since it gets drawn to an overlay). if (g_core->vr_mode()) { @@ -1555,14 +1568,14 @@ void Graphics::SetScreenResolution(float x, float y) { // Need to rebuild internal components (some are sized to the screen). internal_components_inited_ = false; - // Inform all our logic thread buddies of this change. - g_base->logic->OnScreenSizeChange(res_x_virtual_, res_y_virtual_, res_x_, - res_y_); - // This may trigger us sending initial graphics settings to the // graphics-server to kick off drawing. got_screen_resolution_ = true; UpdateInitialGraphicsSettingsSend_(); + + // Inform all our logic thread buddies of virtual/physical res changes. + g_base->logic->OnScreenSizeChange(res_x_virtual_, res_y_virtual_, res_x_, + res_y_); } auto Graphics::CubeMapFromReflectionType(ReflectionType reflection_type) @@ -1723,10 +1736,6 @@ void Graphics::DrawUIBounds(RenderPass* pass) { c.SetColor(1, 0, 0); { auto xf = c.ScopedTransform(); - // float width = pass->virtual_width(); - // float height = pass->virtual_height(); - - // printf("DIMS %.2f %.2f\n", width, height); float width, height; if (g_base->ui->scale() == UIScale::kSmall) { diff --git a/src/ballistica/base/graphics/graphics.h b/src/ballistica/base/graphics/graphics.h index 5fc0c02c..73072734 100644 --- a/src/ballistica/base/graphics/graphics.h +++ b/src/ballistica/base/graphics/graphics.h @@ -15,9 +15,8 @@ #include "ballistica/shared/foundation/object.h" #include "ballistica/shared/foundation/types.h" #include "ballistica/shared/generic/snapshot.h" -#include "ballistica/shared/math/matrix44f.h" -#include "ballistica/shared/math/rect.h" #include "ballistica/shared/math/vector2f.h" +#include "ballistica/shared/math/vector3f.h" namespace ballistica::base { @@ -63,10 +62,13 @@ class Graphics { void OnScreenSizeChange(); void DoApplyAppConfig(); - /// Should be called by the app-adapter to keep the engine informed - /// on the drawable area it has to work with (in pixels). + /// Should be called by the app-adapter to keep the engine informed on the + /// drawable area it has to work with (in pixels). void SetScreenResolution(float x, float y); + /// Should be called when UIScale changes. + void OnUIScaleChange(); + void StepDisplayTime(); auto TextureQualityFromAppConfig() -> TextureQualityRequest; @@ -364,6 +366,7 @@ class Graphics { ScreenMessages* const screenmessages; protected: + void UpdateScreen_(); virtual ~Graphics(); virtual void DoDrawFade(FrameDef* frame_def, float amt); static void CalcVirtualRes_(float* x, float* y); diff --git a/src/ballistica/base/graphics/graphics_server.cc b/src/ballistica/base/graphics/graphics_server.cc index 63220332..08bae26e 100644 --- a/src/ballistica/base/graphics/graphics_server.cc +++ b/src/ballistica/base/graphics/graphics_server.cc @@ -50,9 +50,12 @@ void GraphicsServer::ApplySettings(const GraphicsSettings* settings) { if (renderer_) { renderer_->set_pixel_scale(settings->pixel_scale); } - // Note: not checking virtual res here; assuming it only changes when - // actual res changes. - if (res_x_ != settings->resolution.x || res_y_ != settings->resolution.y) { + // Note: need to look at both physical and virtual res here; its possible + // for physical to stay the same but for virtual to change (ui-scale + // changes can do this). + if (res_x_ != settings->resolution.x || res_y_ != settings->resolution.y + || res_x_virtual_ != settings->resolution_virtual.x + || res_y_virtual_ != settings->resolution_virtual.y) { res_x_ = settings->resolution.x; res_y_ = settings->resolution.y; res_x_virtual_ = settings->resolution_virtual.x; diff --git a/src/ballistica/base/graphics/graphics_vr.cc b/src/ballistica/base/graphics/graphics_vr.cc index ab60fcdd..f4717fab 100644 --- a/src/ballistica/base/graphics/graphics_vr.cc +++ b/src/ballistica/base/graphics/graphics_vr.cc @@ -3,6 +3,7 @@ #include "ballistica/base/graphics/graphics_vr.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/object_component.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/graphics/component/special_component.h" diff --git a/src/ballistica/base/graphics/renderer/render_pass.cc b/src/ballistica/base/graphics/renderer/render_pass.cc index 39446f9c..e8bfd9b5 100644 --- a/src/ballistica/base/graphics/renderer/render_pass.cc +++ b/src/ballistica/base/graphics/renderer/render_pass.cc @@ -472,13 +472,13 @@ void RenderPass::SetFrustum(float near_val, float far_val) { } else { // Old angle-based stuff: float x; - float angleY = (cam_fov_y_ / 2.0f) * kPi / 180.0f; - float y = near_val * tanf(angleY); + float angle_y = (cam_fov_y_ / 2.0f) * kPi / 180.0f; + float y = near_val * tanf(angle_y); // Fov-x < 0 implies to use aspect ratio. if (cam_fov_x_ > 0.0f) { - float angleX = (cam_fov_x_ / 2.0f) * kPi / 180.0f; - x = near_val * tanf(angleX); + float angle_x = (cam_fov_x_ / 2.0f) * kPi / 180.0f; + x = near_val * tanf(angle_x); } else { x = y * GetPhysicalAspectRatio(); } diff --git a/src/ballistica/base/graphics/support/camera.cc b/src/ballistica/base/graphics/support/camera.cc index 483429bc..39b9b934 100644 --- a/src/ballistica/base/graphics/support/camera.cc +++ b/src/ballistica/base/graphics/support/camera.cc @@ -328,10 +328,10 @@ void Camera::UpdatePosition() { x_clamped_focus, y_clamped_focus, z_clamped_focus); } - // Now, for camera aiming purposes, add some of their velocity and - // clamp to the bounds, taking their radius into account. if our AOI - // sphere is bigger than a given dimension, center it; otherwise - // clamp to the box inset by our radius. + // Now, for camera aiming purposes, add some of their velocity + // and clamp to the bounds, taking their radius into account. if + // our AOI sphere is bigger than a given dimension, center it; + // otherwise clamp to the box inset by our radius. float x_clamped, y_clamped, z_clamped, x_mirrored_clamped; float diameter = i.radius() * 2.0f; @@ -371,9 +371,9 @@ void Camera::UpdatePosition() { i.position().z)); } - // Let's also do a version mirrored across the camera's x coordinate - // (adding this to our tracked point set causes us zoom out instead - // of rotating generally) + // Let's also do a version mirrored across the camera's x + // coordinate (adding this to our tracked point set causes us + // zoom out instead of rotating generally) float x_mirrored = position_.x - (i.position().x - position_.x); if (diameter > (area_of_interest_bounds_[3] - area_of_interest_bounds_[0])) { @@ -395,8 +395,8 @@ void Camera::UpdatePosition() { z_clamped - position_.z}; // For sample 0, subtract AOI radius in camera-space x and y. - // For sample 1, add them. - // this way we should get the whole sphere. + // For sample 1, add them. this way we should get the whole + // sphere. if (sample == 0) { to_point -= corner_offs; } else if (sample == 1) { @@ -607,7 +607,6 @@ void Camera::Update(millisecs_t elapsed) { float damping2 = 0.006f; float xy_blend_speed = 0.0002f; time_ += elapsed; - // millisecs_t real_time = g_core->GetAppTimeMillisecs(); // Prevent camera "explosions" if we've been unable to update for a while. elapsed = std::min(millisecs_t{100}, elapsed); @@ -676,8 +675,8 @@ void Camera::Update(millisecs_t elapsed) { elapsedf * rand_component * 4.0f * (-0.5f + RandomFloat()); } - // If we have no important areas of interest, keep our camera from moving too - // fast. + // If we have no important areas of interest, keep our camera from moving + // too fast. if (!have_real_areas_of_interest_) { speed *= 0.5f; } @@ -952,7 +951,9 @@ void Camera::ApplyToFrameDef(FrameDef* frame_def) { float final_fov_y2 = final_fov_x / render_ratio; // If we're not smoothing this frame, snap immediately. - if (!smooth_next_frame_) xy_constrain_blend_ = x_constrained_ ? 1.0f : 0.0f; + if (!smooth_next_frame_) { + xy_constrain_blend_ = x_constrained_ ? 1.0f : 0.0f; + } // We smoothly blend between our x-constrained and non-x-constrained y values // so that we don't see a hitch when it switches. diff --git a/src/ballistica/base/graphics/support/frame_def.h b/src/ballistica/base/graphics/support/frame_def.h index 8ad5b9d2..e962f48b 100644 --- a/src/ballistica/base/graphics/support/frame_def.h +++ b/src/ballistica/base/graphics/support/frame_def.h @@ -7,6 +7,7 @@ #include #include "ballistica/base/assets/asset.h" +#include "ballistica/base/graphics/support/graphics_settings.h" #include "ballistica/shared/generic/snapshot.h" #include "ballistica/shared/math/matrix44f.h" #include "ballistica/shared/math/vector2f.h" diff --git a/src/ballistica/base/graphics/support/net_graph.cc b/src/ballistica/base/graphics/support/net_graph.cc index 445f28ac..409fbfa2 100644 --- a/src/ballistica/base/graphics/support/net_graph.cc +++ b/src/ballistica/base/graphics/support/net_graph.cc @@ -5,6 +5,9 @@ #include #include "ballistica/base/graphics/component/simple_component.h" +#include "ballistica/base/graphics/mesh/image_mesh.h" +#include "ballistica/base/graphics/mesh/mesh_indexed_simple_full.h" +#include "ballistica/base/graphics/text/text_group.h" namespace ballistica::base { diff --git a/src/ballistica/base/graphics/support/screen_messages.cc b/src/ballistica/base/graphics/support/screen_messages.cc index 4ebe74ae..83a3f519 100644 --- a/src/ballistica/base/graphics/support/screen_messages.cc +++ b/src/ballistica/base/graphics/support/screen_messages.cc @@ -2,9 +2,11 @@ #include "ballistica/base/graphics/support/screen_messages.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/text/text_graphics.h" +#include "ballistica/base/graphics/text/text_group.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/generic/utils.h" diff --git a/src/ballistica/base/input/device/touch_input.cc b/src/ballistica/base/input/device/touch_input.cc index eb3af190..b940e20a 100644 --- a/src/ballistica/base/input/device/touch_input.cc +++ b/src/ballistica/base/input/device/touch_input.cc @@ -2,6 +2,7 @@ #include "ballistica/base/input/device/touch_input.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/graphics/support/camera.h" #include "ballistica/base/input/input.h" diff --git a/src/ballistica/base/logic/logic.cc b/src/ballistica/base/logic/logic.cc index b6516c57..2a2bbc79 100644 --- a/src/ballistica/base/logic/logic.cc +++ b/src/ballistica/base/logic/logic.cc @@ -2,6 +2,8 @@ #include "ballistica/base/logic/logic.h" +#include + #include "ballistica/base/app_adapter/app_adapter.h" #include "ballistica/base/app_mode/app_mode.h" #include "ballistica/base/audio/audio.h" @@ -9,12 +11,12 @@ #include "ballistica/base/networking/networking.h" #include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/base_python.h" +#include "ballistica/base/support/context.h" #include "ballistica/base/support/plus_soft.h" #include "ballistica/base/support/stdio_console.h" #include "ballistica/base/ui/dev_console.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/foundation/event_loop.h" -#include "ballistica/shared/python/python_sys.h" namespace ballistica::base { diff --git a/src/ballistica/base/logic/logic.h b/src/ballistica/base/logic/logic.h index e2af720e..58cf8d0c 100644 --- a/src/ballistica/base/logic/logic.h +++ b/src/ballistica/base/logic/logic.h @@ -4,9 +4,8 @@ #define BALLISTICA_BASE_LOGIC_LOGIC_H_ #include -#include -#include "ballistica/shared/foundation/object.h" +#include "ballistica/shared/generic/runnable.h" namespace ballistica::base { @@ -117,9 +116,7 @@ class Logic { auto applied_app_config() const { return applied_app_config_; } auto shutting_down() const { return shutting_down_; } auto shutdown_completed() const { return shutdown_completed_; } - auto graphics_ready() const { return graphics_ready_; } - auto app_active() const { return app_active_; } private: diff --git a/src/ballistica/base/python/base_python.h b/src/ballistica/base/python/base_python.h index ed3dc3ed..176db71b 100644 --- a/src/ballistica/base/python/base_python.h +++ b/src/ballistica/base/python/base_python.h @@ -3,6 +3,8 @@ #ifndef BALLISTICA_BASE_PYTHON_BASE_PYTHON_H_ #define BALLISTICA_BASE_PYTHON_BASE_PYTHON_H_ +#include + #include "ballistica/base/base.h" #include "ballistica/shared/python/python_object_set.h" @@ -175,7 +177,6 @@ class BasePython { void SoftImportPlus(); void SoftImportClassic(); - // void SoftImportUIV1(); private: std::set do_once_locations_; diff --git a/src/ballistica/base/python/methods/python_methods_base_1.cc b/src/ballistica/base/python/methods/python_methods_base_1.cc index 4ca96254..6ae95dd7 100644 --- a/src/ballistica/base/python/methods/python_methods_base_1.cc +++ b/src/ballistica/base/python/methods/python_methods_base_1.cc @@ -719,20 +719,6 @@ static auto PyEnv(PyObject* self) -> PyObject* { // Just build this once and recycle it. if (!g_base->python->objs().Exists(BasePython::ObjID::kEnv)) { - const char* ui_scale; - switch (g_base->ui->scale()) { - case UIScale::kLarge: - ui_scale = "large"; - break; - case UIScale::kMedium: - ui_scale = "medium"; - break; - case UIScale::kSmall: - ui_scale = "small"; - break; - default: - throw Exception(); - } std::optional user_py_dir = g_core->GetUserPythonDirectory(); std::optional app_py_dir = g_core->GetAppPythonDirectory(); std::optional site_py_dir = g_core->GetSitePythonDirectory(); @@ -751,7 +737,6 @@ static auto PyEnv(PyObject* self) -> PyObject* { "sO" // python_directory_app "ss" // platform "ss" // subplatform - "ss" // ui_scale "sO" // on_tv "sO" // vr_mode "sO" // demo_mode @@ -774,7 +759,6 @@ static auto PyEnv(PyObject* self) -> PyObject* { app_py_dir ? *PythonRef::FromString(*app_py_dir) : Py_None, "platform", g_core->platform->GetPlatformName().c_str(), "subplatform", g_core->platform->GetSubplatformName().c_str(), - "ui_scale", ui_scale, "on_tv", g_core->platform->IsRunningOnTV() ? Py_True : Py_False, "vr_mode", g_core->vr_mode() ? Py_True : Py_False, "demo_mode", g_buildconfig.demo_build() ? Py_True : Py_False, diff --git a/src/ballistica/base/python/methods/python_methods_base_3.cc b/src/ballistica/base/python/methods/python_methods_base_3.cc index b0f79be9..e3ff2dbe 100644 --- a/src/ballistica/base/python/methods/python_methods_base_3.cc +++ b/src/ballistica/base/python/methods/python_methods_base_3.cc @@ -7,7 +7,7 @@ #include "ballistica/base/app_adapter/app_adapter.h" #include "ballistica/base/app_mode/app_mode.h" -#include "ballistica/base/assets/sound_asset.h" +#include "ballistica/base/assets/sound_asset.h" // IWYU pragma: keep. #include "ballistica/base/input/input.h" #include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/base_python.h" @@ -62,7 +62,7 @@ static PyMethodDef PyGetSimpleSoundDef = { static auto PySetUIInputDevice(PyObject* self, PyObject* args, PyObject* keywds) -> PyObject* { BA_PYTHON_TRY; - assert(g_base->InLogicThread()); + BA_PRECONDITION(g_base->InLogicThread()); static const char* kwlist[] = {"input_device_id", nullptr}; PyObject* input_device_id_obj = Py_None; if (!PyArg_ParseTupleAndKeywords(args, keywds, "O", @@ -97,6 +97,89 @@ static PyMethodDef PySetUIInputDeviceDef = { "Sets the input-device that currently owns the user interface.", }; +// ------------------------------ set_ui_scale --------------------------------- + +static auto PySetUIScale(PyObject* self, PyObject* args, + PyObject* keywds) -> PyObject* { + BA_PYTHON_TRY; + BA_PRECONDITION(g_base->InLogicThread()); + + const char* scalestr; + + static const char* kwlist[] = {"scale", nullptr}; + PyObject* input_device_id_obj = Py_None; + if (!PyArg_ParseTupleAndKeywords(args, keywds, "s", + const_cast(kwlist), &scalestr)) { + return nullptr; + } + + // FIXME: Should have this take an enum directly once we have an easy way + // to share enums between Python/CPP. + UIScale scale; + if (!strcmp(scalestr, "small")) { + scale = UIScale::kSmall; + } else if (!strcmp(scalestr, "medium")) { + scale = UIScale::kMedium; + } else if (!strcmp(scalestr, "large")) { + scale = UIScale::kLarge; + } else { + throw Exception("Invalid scale value.", PyExcType::kValue); + } + g_base->SetUIScale(scale); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +static PyMethodDef PySetUIScaleDef = { + "set_ui_scale", // name + (PyCFunction)PySetUIScale, // method + METH_VARARGS | METH_KEYWORDS, // flags + + "set_ui_scale(scale: str)" + " -> None\n" + "\n" + "(internal)\n", +}; +// ------------------------------ set_ui_scale --------------------------------- + +static auto PyGetUIScale(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + BA_PRECONDITION(g_base->InLogicThread()); + + // FIXME: Should have this return enums directly once we have an easy way + // to share enums between Python/CPP. + auto scale = g_base->ui->scale(); + + const char* val; + switch (scale) { + case UIScale::kSmall: + val = "small"; + break; + case UIScale::kMedium: + val = "medium"; + break; + case UIScale::kLarge: + val = "large"; + break; + default: + throw Exception("Unhandled scale value."); + } + return PyUnicode_FromString(val); + + BA_PYTHON_CATCH; +} + +static PyMethodDef PyGetUIScaleDef = { + "get_ui_scale", // name + (PyCFunction)PyGetUIScale, // method + METH_NOARGS, // flags + + "get_ui_scale()" + " -> str\n" + "\n" + "(internal)\n", +}; + // ----------------------------- hastouchscreen -------------------------------- static auto PyHasTouchScreen(PyObject* self, PyObject* args, @@ -1899,10 +1982,6 @@ static auto PySetDrawUIBounds(PyObject* self, PyObject* args, return nullptr; } - // if (g_base->graphics->draw_ui_bounds()) { - // Py_RETURN_TRUE; - // } - // Py_RETURN_FALSE; g_base->graphics->set_draw_ui_bounds(value); Py_RETURN_NONE; @@ -1978,6 +2057,8 @@ auto PythonMoethodsBase3::GetMethods() -> std::vector { PyGetIdleTimeDef, PyExtraHashValueDef, PySetUIInputDeviceDef, + PyGetUIScaleDef, + PySetUIScaleDef, PyGetThreadNameDef, PySetThreadNameDef, PyInLogicThreadDef, diff --git a/src/ballistica/base/ui/dev_console.cc b/src/ballistica/base/ui/dev_console.cc index 00c938c4..abb2b810 100644 --- a/src/ballistica/base/ui/dev_console.cc +++ b/src/ballistica/base/ui/dev_console.cc @@ -2,6 +2,8 @@ #include "ballistica/base/ui/dev_console.h" +#include + #include "ballistica/base/app_adapter/app_adapter.h" #include "ballistica/base/app_mode/app_mode.h" #include "ballistica/base/audio/audio.h" @@ -11,12 +13,12 @@ #include "ballistica/base/logic/logic.h" #include "ballistica/base/platform/base_platform.h" #include "ballistica/base/python/base_python.h" +#include "ballistica/base/support/context.h" #include "ballistica/base/support/repeater.h" #include "ballistica/base/ui/ui.h" #include "ballistica/shared/foundation/event_loop.h" #include "ballistica/shared/generic/utils.h" #include "ballistica/shared/python/python_command.h" -#include "ballistica/shared/python/python_sys.h" namespace ballistica::base { @@ -29,11 +31,11 @@ const float kDevConsoleTabButtonCornerRadius{16.0f}; const double kTransitionSeconds{0.15}; enum class DevConsoleHAnchor_ { kLeft, kCenter, kRight }; -enum class DevButtonStyle_ { kNormal, kDark }; +enum class DevButtonStyle_ { kNormal, kLight }; static auto DevButtonStyleFromStr_(const char* strval) { - if (!strcmp(strval, "dark")) { - return DevButtonStyle_::kDark; + if (!strcmp(strval, "light")) { + return DevButtonStyle_::kLight; } assert(!strcmp(strval, "normal")); return DevButtonStyle_::kNormal; @@ -245,11 +247,11 @@ class DevConsole::Button_ : public DevConsole::Widget_ { Vector3f fgcolor; Vector3f bgcolor; switch (style) { - case DevButtonStyle_::kDark: + case DevButtonStyle_::kLight: fgcolor = - pressed ? Vector3f{0.0f, 0.0f, 0.0f} : Vector3f{0.8f, 0.7f, 0.8f}; + pressed ? Vector3f{0.0f, 0.0f, 0.0f} : Vector3f{0.9f, 0.8f, 0.9f}; bgcolor = - pressed ? Vector3f{0.6f, 0.5f, 0.6f} : Vector3f{0.16, 0.07f, 0.18f}; + pressed ? Vector3f{0.8f, 0.7f, 0.8f} : Vector3f{0.4, 0.33f, 0.5f}; break; default: assert(style == DevButtonStyle_::kNormal); @@ -454,6 +456,13 @@ DevConsole::DevConsole() { prompt_text_group_.SetText(">"); } +void DevConsole::OnUIScaleChanged() { + g_base->logic->event_loop()->PushCall([this] { + RefreshTabButtons_(); + RefreshTabContents_(); + }); +} + void DevConsole::RefreshTabButtons_() { // IMPORTANT: This code should always be run in its own top level call and // never directly from user code. Otherwise we can wind up mucking with diff --git a/src/ballistica/base/ui/dev_console.h b/src/ballistica/base/ui/dev_console.h index 61b778cf..032bfe49 100644 --- a/src/ballistica/base/ui/dev_console.h +++ b/src/ballistica/base/ui/dev_console.h @@ -68,6 +68,8 @@ class DevConsole { auto BaseScale() const -> float; void RequestRefresh(); + void OnUIScaleChanged(); + private: class ScopedUILock_; class Widget_; diff --git a/src/ballistica/base/ui/ui.cc b/src/ballistica/base/ui/ui.cc index af6ee26c..68773492 100644 --- a/src/ballistica/base/ui/ui.cc +++ b/src/ballistica/base/ui/ui.cc @@ -7,7 +7,7 @@ #include "ballistica/base/app_adapter/app_adapter.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" // IWYU pragma: keep #include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h" #include "ballistica/base/support/app_config.h" @@ -54,11 +54,11 @@ UI::OperationContext::~OperationContext() { assert(runnables_.empty()); } - // Complain if our Finish() call was never run (unless we're being torn - // down due to an exception). - if (!ran_finish_ && !std::current_exception()) { + // Complain if our Finish() call was never run (unless it seems we're being + // torn down as part of stack-unwinding due to an exception). + if (!ran_finish_ && !std::uncaught_exceptions()) { BA_LOG_ERROR_NATIVE_TRACE_ONCE( - "UI::InteractionContext_ being torn down without Complete called."); + "UI::InteractionContext_ being torn down without Finish() called."); } // Our runnables are raw unmanaged pointers; need to explicitly kill them. @@ -140,6 +140,13 @@ UI::UI() { } } } +void UI::SetScale(UIScale val) { + BA_PRECONDITION(g_base->InLogicThread()); + scale_ = val; + if (dev_console_ != nullptr) { + dev_console_->OnUIScaleChanged(); + } +} void UI::StepDisplayTime() { assert(g_base->InLogicThread()); diff --git a/src/ballistica/base/ui/ui.h b/src/ballistica/base/ui/ui.h index bda94f57..00d41a5f 100644 --- a/src/ballistica/base/ui/ui.h +++ b/src/ballistica/base/ui/ui.h @@ -4,11 +4,9 @@ #define BALLISTICA_BASE_UI_UI_H_ #include -#include -#include "ballistica/base/support/context.h" +#include "ballistica/base/graphics/support/frame_def.h" #include "ballistica/base/ui/widget_message.h" -#include "ballistica/shared/generic/timer_list.h" // Predeclare a few things from ui_v1. namespace ballistica::ui_v1 { @@ -114,9 +112,12 @@ class UI { /// These generally only get shown if a joystick of some form is present. auto ShouldShowButtonShortcuts() const -> bool; - /// Overall ui scale for the app. + /// Get overall ui scale for the app. auto scale() const { return scale_; } + /// Set overall ui scale for the app. + void SetScale(UIScale val); + /// Push a generic 'menu press' event, optionally associated with an input /// device (nullptr to specify none). Can be called from any thread. void PushMainMenuPressCall(InputDevice* device); diff --git a/src/ballistica/scene_v1/node/explosion_node.cc b/src/ballistica/scene_v1/node/explosion_node.cc index 7d541db5..d646271f 100644 --- a/src/ballistica/scene_v1/node/explosion_node.cc +++ b/src/ballistica/scene_v1/node/explosion_node.cc @@ -2,6 +2,7 @@ #include "ballistica/scene_v1/node/explosion_node.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/object_component.h" #include "ballistica/base/graphics/component/post_process_component.h" #include "ballistica/base/graphics/support/camera.h" diff --git a/src/ballistica/scene_v1/node/flash_node.cc b/src/ballistica/scene_v1/node/flash_node.cc index 93324da7..73e79871 100644 --- a/src/ballistica/scene_v1/node/flash_node.cc +++ b/src/ballistica/scene_v1/node/flash_node.cc @@ -2,6 +2,7 @@ #include "ballistica/scene_v1/node/flash_node.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/object_component.h" #include "ballistica/scene_v1/node/node_attribute.h" #include "ballistica/scene_v1/node/node_type.h" diff --git a/src/ballistica/scene_v1/node/locator_node.cc b/src/ballistica/scene_v1/node/locator_node.cc index 59c92dd1..7a829f7c 100644 --- a/src/ballistica/scene_v1/node/locator_node.cc +++ b/src/ballistica/scene_v1/node/locator_node.cc @@ -2,6 +2,7 @@ #include "ballistica/scene_v1/node/locator_node.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/scene_v1/node/node_attribute.h" #include "ballistica/scene_v1/node/node_type.h" diff --git a/src/ballistica/scene_v1/node/scorch_node.cc b/src/ballistica/scene_v1/node/scorch_node.cc index 5fe11ba5..d2b4fa4f 100644 --- a/src/ballistica/scene_v1/node/scorch_node.cc +++ b/src/ballistica/scene_v1/node/scorch_node.cc @@ -2,6 +2,7 @@ #include "ballistica/scene_v1/node/scorch_node.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/scene_v1/node/node_attribute.h" #include "ballistica/scene_v1/node/node_type.h" diff --git a/src/ballistica/scene_v1/node/shield_node.cc b/src/ballistica/scene_v1/node/shield_node.cc index df28bee8..00513cb7 100644 --- a/src/ballistica/scene_v1/node/shield_node.cc +++ b/src/ballistica/scene_v1/node/shield_node.cc @@ -2,6 +2,7 @@ #include "ballistica/scene_v1/node/shield_node.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/object_component.h" #include "ballistica/base/graphics/component/post_process_component.h" #include "ballistica/base/graphics/component/shield_component.h" diff --git a/src/ballistica/shared/ballistica.cc b/src/ballistica/shared/ballistica.cc index 8fee7684..3baecf9f 100644 --- a/src/ballistica/shared/ballistica.cc +++ b/src/ballistica/shared/ballistica.cc @@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int { namespace ballistica { // These are set automatically via script; don't modify them here. -const int kEngineBuildNumber = 21986; +const int kEngineBuildNumber = 22004; const char* kEngineVersion = "1.7.37"; const int kEngineApiVersion = 9; diff --git a/src/ballistica/shared/foundation/macros.h b/src/ballistica/shared/foundation/macros.h index 3ba372e6..946ffe26 100644 --- a/src/ballistica/shared/foundation/macros.h +++ b/src/ballistica/shared/foundation/macros.h @@ -4,7 +4,6 @@ #define BALLISTICA_SHARED_FOUNDATION_MACROS_H_ #ifdef __cplusplus -#include #include #endif diff --git a/src/ballistica/shared/foundation/types.h b/src/ballistica/shared/foundation/types.h index 805fd579..6789d009 100644 --- a/src/ballistica/shared/foundation/types.h +++ b/src/ballistica/shared/foundation/types.h @@ -142,9 +142,9 @@ typedef int64_t TimerMedium; /// content needs to be presented as large and clear in order to remain /// readable from an average distance. enum class UIScale : uint8_t { - kLarge, - kMedium, kSmall, + kMedium, + kLarge, kLast // Sentinel. }; diff --git a/src/ballistica/shared/python/python_sys.h b/src/ballistica/shared/python/python_sys.h index 220a4726..774e9105 100644 --- a/src/ballistica/shared/python/python_sys.h +++ b/src/ballistica/shared/python/python_sys.h @@ -7,12 +7,13 @@ // This header pulls in the actual Python includes and also defines some handy // macros and functions for working with Python objects. -// This is the ONE place we actually include Python. +// UPDATE (September 2024): We now include Python.h directly in some places; +// this causes less friction with include-what-you-use checks. #include #include #include -#include +#include // IWYU pragma: keep. (macros below use this) // Saving/restoring Python error state; useful when function PyObject_Str() // or other functionality is needed during error reporting; by default it diff --git a/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc b/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc index ca7d6862..5e87695e 100644 --- a/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc +++ b/src/ballistica/ui_v1/python/methods/python_methods_ui_v1.cc @@ -2,11 +2,9 @@ #include "ballistica/ui_v1/python/methods/python_methods_ui_v1.h" -#include "ballistica/base/app_adapter/app_adapter.h" -#include "ballistica/base/app_mode/app_mode.h" -#include "ballistica/base/assets/sound_asset.h" -#include "ballistica/base/platform/base_platform.h" +#include "ballistica/base/assets/sound_asset.h" // IWYU pragma: keep. #include "ballistica/base/python/base_python.h" +#include "ballistica/base/support/context.h" #include "ballistica/shared/foundation/macros.h" #include "ballistica/ui_v1/python/class/python_class_ui_mesh.h" #include "ballistica/ui_v1/python/class/python_class_ui_sound.h" @@ -581,7 +579,7 @@ static auto PyCheckBoxWidget(PyObject* self, PyObject* args, widget = Object::New(); } - // set applicable values ---------------------------- + // Set applicable values. if (size_obj != Py_None) { Point2D p = Python::GetPyPoint2D(size_obj); widget->SetWidth(p.x); @@ -1022,7 +1020,7 @@ static auto PyColumnWidget(PyObject* self, PyObject* args, widget->set_claims_tab(Python::GetPyBool(claims_tab_obj)); } - // if making a new widget add it at the end + // If making a new widget, add it at the end. if (edit_obj == Py_None) { g_ui_v1->AddWidget(widget.Get(), parent_widget); } @@ -1357,6 +1355,7 @@ static auto PyContainerWidget(PyObject* self, PyObject* args, ui_op_context.Finish(); return widget->NewPyRef(); + BA_PYTHON_CATCH; } @@ -1628,7 +1627,7 @@ static auto PyScrollWidget(PyObject* self, PyObject* args, widget = Object::New(); } - // Set applicable values. ---------------------------- + // Set applicable values. if (size_obj != Py_None) { Point2D p = Python::GetPyPoint2D(size_obj); widget->SetWidth(p.x); @@ -2587,35 +2586,6 @@ static PyMethodDef PyRootUIBackPressDef = { "(internal)", }; -// ------------------------ is_party_icon_visible ------------------------------ - -static auto PyIsPartyIconVisible(PyObject* self) -> PyObject* { - BA_PYTHON_TRY; - BA_PRECONDITION(g_base->InLogicThread()); - bool party_button_active = (g_base->app_mode()->HasConnectionToClients() - || g_base->app_mode()->HasConnectionToHost()); - // bool party_button_active = (g_base->app_mode()->HasConnectionToClients() - // || g_base->app_mode()->HasConnectionToHost() - // || - // g_ui_v1->root_ui()->always_draw_party_icon()); - if (party_button_active) { - Py_RETURN_TRUE; - } else { - Py_RETURN_FALSE; - } - BA_PYTHON_CATCH; -} - -static PyMethodDef PyIsPartyIconVisibleDef = { - "is_party_icon_visible", // name - (PyCFunction)PyIsPartyIconVisible, // method - METH_NOARGS, // flags - - "is_party_icon_visible() -> bool\n" - "\n" - "(internal)", -}; - // ----------------------------- is_available ---------------------------------- static auto PyIsAvailable(PyObject* self) -> PyObject* { @@ -2641,30 +2611,38 @@ static PyMethodDef PyIsAvailableDef = { "(internal)", }; +// --------------------------- on_screen_change -------------------------------- + +static auto PyOnScreenChange(PyObject* self) -> PyObject* { + BA_PYTHON_TRY; + BA_PRECONDITION(g_base->InLogicThread()); + + g_ui_v1->OnScreenChange(); + Py_RETURN_NONE; + BA_PYTHON_CATCH; +} + +static PyMethodDef PyOnScreenChangeDef = { + "on_screen_change", // name + (PyCFunction)PyOnScreenChange, // method + METH_NOARGS, // flags + + "on_screen_change() -> None\n" + "\n" + "(internal)", +}; + // ----------------------------------------------------------------------------- auto PythonMethodsUIV1::GetMethods() -> std::vector { return { - PyIsPartyIconVisibleDef, - PyRootUIBackPressDef, - PyGetSpecialWidgetDef, - PySetPartyWindowOpenDef, - PyButtonWidgetDef, - PyCheckBoxWidgetDef, - PyImageWidgetDef, - PyColumnWidgetDef, - PyContainerWidgetDef, - PyRowWidgetDef, - PyScrollWidgetDef, - PyHScrollWidgetDef, - PyTextWidgetDef, - PyWidgetDef, - PyUIBoundsDef, - PyGetSoundDef, - PyGetTextureDef, - PyGetQRCodeTextureDef, - PyGetMeshDef, - PyIsAvailableDef, + PyRootUIBackPressDef, PyGetSpecialWidgetDef, PySetPartyWindowOpenDef, + PyButtonWidgetDef, PyCheckBoxWidgetDef, PyImageWidgetDef, + PyColumnWidgetDef, PyContainerWidgetDef, PyRowWidgetDef, + PyScrollWidgetDef, PyHScrollWidgetDef, PyTextWidgetDef, + PyWidgetDef, PyUIBoundsDef, PyGetSoundDef, + PyGetTextureDef, PyGetQRCodeTextureDef, PyGetMeshDef, + PyIsAvailableDef, PyOnScreenChangeDef, }; } diff --git a/src/ballistica/ui_v1/python/ui_v1_python.cc b/src/ballistica/ui_v1/python/ui_v1_python.cc index b585a962..dd4b616d 100644 --- a/src/ballistica/ui_v1/python/ui_v1_python.cc +++ b/src/ballistica/ui_v1/python/ui_v1_python.cc @@ -3,14 +3,12 @@ #include "ballistica/ui_v1/python/ui_v1_python.h" #include "ballistica/base/audio/audio.h" -#include "ballistica/base/input/device/keyboard_input.h" +#include "ballistica/base/input/device/keyboard_input.h" // IWYU pragma: keep. #include "ballistica/base/input/input.h" -#include "ballistica/base/logic/logic.h" #include "ballistica/base/python/base_python.h" #include "ballistica/base/python/support/python_context_call.h" #include "ballistica/base/ui/dev_console.h" -#include "ballistica/shared/foundation/event_loop.h" -#include "ballistica/shared/python/python_command.h" +#include "ballistica/shared/python/python_command.h" // IWYU pragma: keep. #include "ballistica/shared/python/python_module_builder.h" #include "ballistica/ui_v1/python/class/python_class_ui_mesh.h" #include "ballistica/ui_v1/python/class/python_class_ui_sound.h" @@ -22,9 +20,9 @@ namespace ballistica::ui_v1 { UIV1Python::UIV1Python() = default; -// Declare a plain c PyInit_XXX function for our Python module; -// this is how Python inits our binary module (and by extension, our -// entire feature-set). +// Declare a plain C PyInit_XXX function for our Python module; this is how +// Python inits our binary module (and by extension, our entire +// feature-set). extern "C" auto PyInit__bauiv1() -> PyObject* { auto* builder = new PythonModuleBuilder("_bauiv1", @@ -48,8 +46,8 @@ void UIV1Python::AddPythonClasses(PyObject* module) { } void UIV1Python::ImportPythonObjs() { - // Import and grab all our objs_. - // This code blob expects 'ObjID' and 'objs_' to be defined. + // Import and grab all our objs_. This code blob expects 'ObjID' and + // 'objs_' to be defined. #include "ballistica/ui_v1/mgen/pyembed/binding_ui_v1.inc" } @@ -113,8 +111,8 @@ void UIV1Python::InvokeStringEditor(PyObject* string_edit_adapter_instance) { auto context_call = Object::New( objs().Get(ObjID::kOnScreenKeyboardClass)); - // This is probably getting called from within UI handling, so we - // need to schedule things to run post-ui-traversal in that case. + // This is probably getting called from within UI handling, so we need to + // schedule things to run post-ui-traversal in that case. if (g_base->ui->InUIOperation()) { context_call->ScheduleInUIOperation(args); } else { diff --git a/src/ballistica/ui_v1/ui_v1.cc b/src/ballistica/ui_v1/ui_v1.cc index db224536..b0709536 100644 --- a/src/ballistica/ui_v1/ui_v1.cc +++ b/src/ballistica/ui_v1/ui_v1.cc @@ -2,7 +2,7 @@ #include "ballistica/ui_v1/ui_v1.h" -#include "ballistica/base/app_mode/app_mode.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/input/input.h" #include "ballistica/base/support/app_config.h" @@ -214,12 +214,23 @@ void UIV1FeatureSet::AddWidget(Widget* w, ContainerWidget* parent) { } void UIV1FeatureSet::OnScreenSizeChange() { + // This gets called by the native layer as window is resized/etc. if (root_widget_.Exists()) { root_widget_->SetWidth(g_base->graphics->screen_virtual_width()); root_widget_->SetHeight(g_base->graphics->screen_virtual_height()); } } +void UIV1FeatureSet::OnScreenChange() { + // This gets called by the Python layer when UIScale or window size + // changes. + assert(g_base->InLogicThread()); + + // We allow OnScreenSizeChange() to handle size changes but *do* handle + // UIScale changes here. + root_widget_->OnUIScaleChange(); +} + void UIV1FeatureSet::OnLanguageChange() { // Since switching languages is a bit costly, ignore redundant change // notifications. These will tend to happen nowadays since change diff --git a/src/ballistica/ui_v1/ui_v1.h b/src/ballistica/ui_v1/ui_v1.h index 1ecd406d..f9824c9b 100644 --- a/src/ballistica/ui_v1/ui_v1.h +++ b/src/ballistica/ui_v1/ui_v1.h @@ -85,18 +85,10 @@ class UIV1FeatureSet : public FeatureSetNativeComponent, auto MainMenuVisible() -> bool override; auto PartyIconVisible() -> bool override; void ActivatePartyIcon() override; - // void HandleLegacyRootUIMouseMotion(float x, float y) override; - // auto HandleLegacyRootUIMouseDown(float x, float y) -> bool override; - // void HandleLegacyRootUIMouseUp(float x, float y) override; void Draw(base::FrameDef* frame_def) override; UIV1Python* const python; - // auto root_ui() const -> ui_v1::RootUI* { - // assert(root_ui_); - // return root_ui_; - // } - // void OnAppStart() override; void OnActivate() override; void OnDeactivate() override; @@ -123,6 +115,8 @@ class UIV1FeatureSet : public FeatureSetNativeComponent, void DeleteWidget(Widget* widget); void OnScreenSizeChange() override; + void OnScreenChange(); + void OnLanguageChange() override; auto GetRootWidget() -> ui_v1::Widget* override; auto SendWidgetMessage(const base::WidgetMessage& m) -> int override; @@ -140,7 +134,6 @@ class UIV1FeatureSet : public FeatureSetNativeComponent, private: UIV1FeatureSet(); - // RootUI* root_ui_{}; Object::Ref screen_root_widget_; Object::Ref overlay_root_widget_; Object::Ref root_widget_; diff --git a/src/ballistica/ui_v1/widget/button_widget.cc b/src/ballistica/ui_v1/widget/button_widget.cc index ed243ef9..086b004e 100644 --- a/src/ballistica/ui_v1/widget/button_widget.cc +++ b/src/ballistica/ui_v1/widget/button_widget.cc @@ -2,6 +2,7 @@ #include "ballistica/ui_v1/widget/button_widget.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/graphics/component/simple_component.h" @@ -103,15 +104,11 @@ auto ButtonWidget::GetMult(millisecs_t current_time) const -> float { mult *= 2.0f; } } else { - if (!texture_.Exists()) { - } else { - // In desktop mode we want image buttons to light up when we - // mouse over them. - if (!g_core->platform->IsRunningOnDesktop()) { - if (mouse_over_) { - mult = 1.4f; - } - } + // Slightly highlighting all buttons for mouse-over. Once we can + // differentiate between touch events and pointer events we should limit + // this to pointer events. + if (mouse_over_) { + mult = 1.2f; } } return mult; @@ -459,17 +456,22 @@ void ButtonWidget::Draw(base::RenderPass* pass, bool draw_transparent) { auto ButtonWidget::HandleMessage(const base::WidgetMessage& m) -> bool { // How far outside button touches register. float left_overlap, top_overlap, right_overlap, bottom_overlap; - if (g_core->platform->IsRunningOnDesktop()) { - left_overlap = 3.0f; - top_overlap = 1.0f; - right_overlap = 0.0f; - bottom_overlap = 0.0f; - } else { - left_overlap = 3.0f + 9.0f * extra_touch_border_scale_; - top_overlap = 1.0f + 5.0f * extra_touch_border_scale_; - right_overlap = 7.0f * extra_touch_border_scale_; - bottom_overlap = 7.0f * extra_touch_border_scale_; - } + // if (g_core->platform->IsRunningOnDesktop()) { + + // UPDATE - removing touch-specific boundary adjustments. If it is + // necessary to reenable these, should do it on a per-event basis so need + // to differentiate between touches and clicks. It is probably sufficient + // to simply expose manual boundary tweaks that apply everywhere though. + left_overlap = 3.0f; + top_overlap = 1.0f; + right_overlap = 0.0f; + bottom_overlap = 0.0f; + // } else { + // left_overlap = 3.0f + 9.0f * extra_touch_border_scale_; + // top_overlap = 1.0f + 5.0f * extra_touch_border_scale_; + // right_overlap = 7.0f * extra_touch_border_scale_; + // bottom_overlap = 7.0f * extra_touch_border_scale_; + // } // Extra overlap that always applies. right_overlap += target_extra_right_; diff --git a/src/ballistica/ui_v1/widget/container_widget.cc b/src/ballistica/ui_v1/widget/container_widget.cc index a2934beb..baa3f225 100644 --- a/src/ballistica/ui_v1/widget/container_widget.cc +++ b/src/ballistica/ui_v1/widget/container_widget.cc @@ -2,6 +2,7 @@ #include "ballistica/ui_v1/widget/container_widget.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/graphics/component/simple_component.h" @@ -349,8 +350,6 @@ auto ContainerWidget::HandleMessage(const base::WidgetMessage& m) -> bool { // Schedule this to run immediately after any current UI // traversal. call->ScheduleInUIOperation(); - } else { - OnCancelCustom(); } } break; @@ -1407,7 +1406,7 @@ void ContainerWidget::SelectWidget(Widget* w, SelectionCause c) { } for (auto& widget : widgets_) { if (&(*widget) == w) { - Widget* prevSelectedWidget = selected_widget_; + Widget* prev_selected_widget = selected_widget_; // Deactivate old selected widget. if (selected_widget_) { @@ -1421,8 +1420,8 @@ void ContainerWidget::SelectWidget(Widget* w, SelectionCause c) { // Store the old one as prev-selected if its not the one we're // selecting now. (otherwise re-selecting repeatedly kills our prev // mechanism). - if (prevSelectedWidget != selected_widget_) { - prev_selected_widget_ = prevSelectedWidget; + if (prev_selected_widget != selected_widget_) { + prev_selected_widget_ = prev_selected_widget; } } else { static bool printed = false; diff --git a/src/ballistica/ui_v1/widget/container_widget.h b/src/ballistica/ui_v1/widget/container_widget.h index 5f55bd7e..db30a439 100644 --- a/src/ballistica/ui_v1/widget/container_widget.h +++ b/src/ballistica/ui_v1/widget/container_widget.h @@ -36,8 +36,8 @@ class ContainerWidget : public Widget { void SetStartButton(ButtonWidget* button); void SetOnCancelCall(PyObject* call_tuple); - // Set a widget to selected (must already have been added to dialog) - // Pass nullptr to deselect widgets. + // Set a widget to selected (must already have been added to dialog). Pass + // nullptr to deselect widgets. void SelectWidget(Widget* w, SelectionCause s = SelectionCause::NONE); void ReselectLastSelectedWidget(); void ShowWidget(Widget* w); @@ -118,12 +118,6 @@ class ContainerWidget : public Widget { // (generally true but list containers may not want) auto selection_loops() const -> bool { return selection_loops_; } - // If the selection doesn't loop, returns whether a selection loop transfers - // the message to the parent instead. - auto selection_loops_to_parent() const -> bool { - return selection_loops_to_parent_; - } - void SetOnActivateCall(PyObject* c); void SetOnOutsideClickCall(PyObject* c); @@ -132,13 +126,23 @@ class ContainerWidget : public Widget { } void set_draggable(bool d) { draggable_ = d; } - void set_claims_tab(bool c) { claims_tab_ = c; } - void set_claims_left_right(bool c) { claims_left_right_ = c; } - void set_claims_up_down(bool c) { claims_up_down_ = c; } - void set_selection_loops_to_parent(bool d) { selection_loops_to_parent_ = d; } + auto claims_tab() const -> bool { return claims_tab_; } + void set_claims_tab(bool c) { claims_tab_ = c; } + auto claims_left_right() const -> bool { return claims_left_right_; } + void set_claims_left_right(bool c) { claims_left_right_ = c; } + auto claims_up_down() const -> bool { return claims_up_down_; } + void set_claims_up_down(bool c) { claims_up_down_ = c; } + + // If the selection doesn't loop, returns whether a selection loop + // transfers the message to the parent instead. + auto selection_loops_to_parent() const -> bool { + return selection_loops_to_parent_; + } + void set_selection_loops_to_parent(bool d) { selection_loops_to_parent_ = d; } + void set_single_depth(bool s) { single_depth_ = s; } // Translate a point in-place into the space of a given child widget. @@ -151,33 +155,33 @@ class ContainerWidget : public Widget { blue_ = b; alpha_ = a; } - void set_should_print_list_exit_instructions(bool v) { - should_print_list_exit_instructions_ = v; - } + auto GetDrawBrightness(millisecs_t time) const -> float override; + auto IsAcceptingInput() const -> bool override; + void OnLanguageChange() override; + void set_selection_loops(bool loops) { selection_loops_ = loops; } void set_click_activate(bool enabled) { click_activate_ = enabled; } void set_always_highlight(bool enable) { always_highlight_ = enable; } - auto GetDrawBrightness(millisecs_t time) const -> float override; - auto IsAcceptingInput() const -> bool override; void set_claims_outside_clicks(bool val) { claims_outside_clicks_ = val; } - void OnLanguageChange() override; - void set_is_overlay_window_stack(bool val) { is_overlay_window_stack_ = val; } void set_is_main_window_stack(bool val) { is_main_window_stack_ = val; } + void set_should_print_list_exit_instructions(bool v) { + should_print_list_exit_instructions_ = v; + } - // Return the topmost widget that is accepting input. - // (used for toolbar focusing; may not always equal selected widget - // if the topmost one is transitioning out, etc.) + // Return the topmost widget that is accepting input. Used for toolbar + // focusing; may not always equal selected widget if the topmost one is + // transitioning out, etc. auto GetTopmostToolbarInfluencingWidget() -> Widget*; auto IsTransitioningOut() const -> bool override; protected: - virtual void OnCancelCustom() {} void set_single_depth_root(bool s) { single_depth_root_ = s; } - // Note that the offsets here are purely for visual transitions and things; - // the UI itself only knows about the standard widget transform values. + // Note that the offsets here are purely for visual transitions and + // things; the UI itself only knows about the standard widget transform + // values. void DrawChildren(base::RenderPass* pass, bool transparent, float x_offset, float y_offset, float scale); void SetSelected(bool s, SelectionCause cause) override; @@ -195,41 +199,36 @@ class ContainerWidget : public Widget { void set_height(float val) { height_ = val; } private: - // Given a container and a point, returns a selectable widget in the downward - // direction or nullptr. + // Given a container and a point, returns a selectable widget in the + // downward direction or nullptr. auto GetClosestDownWidget(float x, float y, Widget* ignoreWidget) -> Widget*; auto GetClosestUpWidget(float x, float y, Widget* ignoreWidget) -> Widget*; auto GetClosestRightWidget(float x, float y, Widget* ignoreWidget) -> Widget*; auto GetClosestLeftWidget(float x, float y, Widget* ignoreWidget) -> Widget*; auto GetMult(millisecs_t current_time, bool for_glow = false) const -> float; void PrintExitListInstructions(millisecs_t old_last_prev_next_time); + std::vector > widgets_; + Object::Ref tex_; + Object::WeakRef cancel_button_; + Object::WeakRef start_button_; + Widget* selected_widget_{}; + Widget* prev_selected_widget_{}; + base::SysMeshID bg_mesh_transparent_i_d_{}; + base::SysMeshID bg_mesh_opaque_i_d_{}; + TransitionType transition_type_{}; float width_{}; float height_{}; - bool modal_children_{}; - bool selection_loops_{true}; - bool is_main_window_stack_{}; - bool is_overlay_window_stack_{}; float scale_origin_stack_offset_x_{}; float scale_origin_stack_offset_y_{}; float transition_scale_offset_x_{}; float transition_scale_offset_y_{}; - bool pressed_{}; - bool mouse_over_{}; - bool pressed_activate_{}; - bool always_highlight_{}; - bool click_activate_{}; float red_{0.4f}; float green_{0.37f}; float blue_{0.49f}; float alpha_{1.0f}; - Object::Ref tex_; - base::SysMeshID bg_mesh_transparent_i_d_{}; - base::SysMeshID bg_mesh_opaque_i_d_{}; float glow_width_{}, glow_height_{}, glow_center_x_{}, glow_center_y_{}; float bg_width_{}, bg_height_{}, bg_center_x_{}, bg_center_y_{}; - millisecs_t last_activate_time_millisecs_{}; - millisecs_t transition_start_time_{}; float transition_target_offset_{}; float drag_x_{}, drag_y_{}; float transition_offset_x_{}; @@ -241,11 +240,23 @@ class ContainerWidget : public Widget { float transition_start_offset_{}; float transition_scale_{1.0f}; float d_transition_scale_{}; + millisecs_t last_activate_time_millisecs_{}; + millisecs_t transition_start_time_{}; millisecs_t dynamics_update_time_millisecs_{}; + millisecs_t last_prev_next_time_millisecs_{}; + millisecs_t last_list_exit_instructions_print_time_{}; + bool modal_children_{}; + bool selection_loops_{true}; + bool is_main_window_stack_{}; + bool is_overlay_window_stack_{}; bool bg_dirty_{true}; bool glow_dirty_{true}; bool transitioning_{}; - TransitionType transition_type_{}; + bool pressed_{}; + bool mouse_over_{}; + bool pressed_activate_{}; + bool always_highlight_{}; + bool click_activate_{}; bool transitioning_out_{}; bool draggable_{}; bool dragging_{}; @@ -263,16 +274,10 @@ class ContainerWidget : public Widget { bool single_depth_{true}; bool single_depth_root_{}; bool should_print_list_exit_instructions_{}; - millisecs_t last_prev_next_time_millisecs_{}; - millisecs_t last_list_exit_instructions_print_time_{}; - Widget* selected_widget_{}; - Widget* prev_selected_widget_{}; - Object::WeakRef cancel_button_; - Object::WeakRef start_button_; bool claims_outside_clicks_{}; - // Keep these at the bottom so they're torn down first. - // ...hmm that seems fragile; should I add explicit code to kill them? + // Keep these at the bottom so they're torn down first. ...hmm that seems + // fragile; should I add explicit code to kill them? Object::Ref on_activate_call_; Object::Ref on_outside_click_call_; Object::Ref on_cancel_call_; diff --git a/src/ballistica/ui_v1/widget/h_scroll_widget.cc b/src/ballistica/ui_v1/widget/h_scroll_widget.cc index db2cdd01..b8bbed73 100644 --- a/src/ballistica/ui_v1/widget/h_scroll_widget.cc +++ b/src/ballistica/ui_v1/widget/h_scroll_widget.cc @@ -2,6 +2,7 @@ #include "ballistica/ui_v1/widget/h_scroll_widget.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/support/app_timer.h" diff --git a/src/ballistica/ui_v1/widget/image_widget.cc b/src/ballistica/ui_v1/widget/image_widget.cc index c33446f8..ccaed69e 100644 --- a/src/ballistica/ui_v1/widget/image_widget.cc +++ b/src/ballistica/ui_v1/widget/image_widget.cc @@ -2,7 +2,9 @@ #include "ballistica/ui_v1/widget/image_widget.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/simple_component.h" +#include "ballistica/base/graphics/mesh/mesh_indexed_simple_full.h" #include "ballistica/base/logic/logic.h" namespace ballistica::ui_v1 { diff --git a/src/ballistica/ui_v1/widget/root_widget.cc b/src/ballistica/ui_v1/widget/root_widget.cc index 8028d82d..bf8132f6 100644 --- a/src/ballistica/ui_v1/widget/root_widget.cc +++ b/src/ballistica/ui_v1/widget/root_widget.cc @@ -6,6 +6,7 @@ #include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/renderer/render_pass.h" #include "ballistica/base/graphics/support/frame_def.h" +#include "ballistica/base/support/context.h" #include "ballistica/shared/foundation/inline.h" #include "ballistica/ui_v1/python/ui_v1_python.h" #include "ballistica/ui_v1/widget/button_widget.h" @@ -1574,6 +1575,8 @@ void RootWidget::UpdateLayout() { StepPositions_(0.0f); } +void RootWidget::OnUIScaleChange() { MarkForUpdate(); } + auto RootWidget::HandleMessage(const base::WidgetMessage& m) -> bool { // If a cancel message comes through and our back button is enabled, fire // our back button. In all other cases just do the default. @@ -1607,20 +1610,6 @@ void RootWidget::SetOverlayWidget(StackWidget* w) { overlay_stack_widget_ = w; } -void RootWidget::OnCancelCustom() { - // Need to revisit this. If the cancel event it pushes is not handled, it will - // wind up back here where it pushes another back call. This cycle repeats - // forever until something comes along which does handle cancel events and - // then it gets them all. Current repro case is Sign-in-with-BombSquad-Account - // window - press escape a few times while that is up and then click cancel; - // This code is only used for toolbar mode so should be safe to leave it - // disabled for now. - - // Is there a reason for this to exist? If so, what is it? - // printf("GOT OnCancelCustom\n"); - // g_base->ui->PushBackButtonCall(nullptr); -} - auto RootWidget::GetSpecialWidget(const std::string& s) const -> Widget* { if (s == "squad_button") { return squad_button_ ? squad_button_->widget.Get() : nullptr; diff --git a/src/ballistica/ui_v1/widget/root_widget.h b/src/ballistica/ui_v1/widget/root_widget.h index 272fa71e..29b96978 100644 --- a/src/ballistica/ui_v1/widget/root_widget.h +++ b/src/ballistica/ui_v1/widget/root_widget.h @@ -30,7 +30,9 @@ class RootWidget : public ContainerWidget { return overlay_stack_widget_; } - void OnCancelCustom() override; + /// Called when UIScale or screen dimensions change. + void OnUIScaleChange(); + void UpdateLayout() override; private: diff --git a/src/ballistica/ui_v1/widget/scroll_widget.cc b/src/ballistica/ui_v1/widget/scroll_widget.cc index e4b83766..2204a235 100644 --- a/src/ballistica/ui_v1/widget/scroll_widget.cc +++ b/src/ballistica/ui_v1/widget/scroll_widget.cc @@ -2,6 +2,7 @@ #include "ballistica/ui_v1/widget/scroll_widget.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/support/app_timer.h" diff --git a/src/ballistica/ui_v1/widget/text_widget.cc b/src/ballistica/ui_v1/widget/text_widget.cc index a1caf3e4..4d3046d4 100644 --- a/src/ballistica/ui_v1/widget/text_widget.cc +++ b/src/ballistica/ui_v1/widget/text_widget.cc @@ -2,11 +2,13 @@ #include "ballistica/ui_v1/widget/text_widget.h" +#include "ballistica/base/assets/assets.h" #include "ballistica/base/audio/audio.h" #include "ballistica/base/graphics/component/empty_component.h" #include "ballistica/base/graphics/component/simple_component.h" #include "ballistica/base/graphics/mesh/nine_patch_mesh.h" #include "ballistica/base/graphics/text/text_graphics.h" +#include "ballistica/base/graphics/text/text_group.h" #include "ballistica/base/input/device/keyboard_input.h" #include "ballistica/base/input/input.h" #include "ballistica/base/logic/logic.h"