From 7122180847241af19aebea0a0090afa00666e1f3 Mon Sep 17 00:00:00 2001 From: Eric Date: Thu, 5 Sep 2024 13:47:58 -0700 Subject: [PATCH] wired up dynamic uiscale changes via dev-console --- .efrocachemap | 58 ++++---- CHANGELOG.md | 10 +- config/requirements.txt | 2 +- src/assets/ba_data/python/babase/__init__.py | 6 +- src/assets/ba_data/python/babase/_app.py | 46 +++++- .../ba_data/python/babase/_appsubsystem.py | 5 +- .../ba_data/python/babase/_devconsole.py | 15 +- .../ba_data/python/baclassic/_appmode.py | 3 + .../ba_data/python/baclassic/_appsubsystem.py | 2 + src/assets/ba_data/python/baenv.py | 2 +- .../python/bascenev1lib/activity/coopscore.py | 2 +- src/assets/ba_data/python/bauiv1/__init__.py | 2 - .../ba_data/python/bauiv1/_appsubsystem.py | 139 ++++++++++++------ src/assets/ba_data/python/bauiv1/_uitypes.py | 22 ++- .../python/bauiv1lib/settings/devtools.py | 66 +++++---- src/assets/ba_data/python/bauiv1lib/watch.py | 2 +- .../base/app_mode/empty_app_mode.cc | 1 + src/ballistica/base/base.cc | 19 ++- src/ballistica/base/base.h | 4 +- .../base/dynamics/collision_cache.cc | 1 + .../graphics/component/object_component.cc | 2 + .../graphics/component/render_component.cc | 2 + .../graphics/component/render_component.h | 7 +- .../graphics/component/simple_component.cc | 2 + .../graphics/component/smoke_component.cc | 2 + .../graphics/component/sprite_component.cc | 2 + .../base/graphics/gl/renderer_gl.cc | 2 +- src/ballistica/base/graphics/graphics.cc | 31 ++-- src/ballistica/base/graphics/graphics.h | 11 +- .../base/graphics/graphics_server.cc | 9 +- src/ballistica/base/graphics/graphics_vr.cc | 1 + .../base/graphics/support/frame_def.h | 1 + .../base/graphics/support/net_graph.cc | 3 + .../base/graphics/support/screen_messages.cc | 2 + .../base/input/device/touch_input.cc | 1 + src/ballistica/base/logic/logic.cc | 4 +- src/ballistica/base/logic/logic.h | 5 +- src/ballistica/base/python/base_python.h | 3 +- .../python/methods/python_methods_base_1.cc | 16 -- .../python/methods/python_methods_base_3.cc | 93 +++++++++++- src/ballistica/base/ui/dev_console.cc | 11 +- src/ballistica/base/ui/dev_console.h | 2 + src/ballistica/base/ui/ui.cc | 7 + src/ballistica/base/ui/ui.h | 9 +- .../scene_v1/node/explosion_node.cc | 1 + src/ballistica/scene_v1/node/flash_node.cc | 1 + src/ballistica/scene_v1/node/locator_node.cc | 1 + src/ballistica/scene_v1/node/scorch_node.cc | 1 + src/ballistica/scene_v1/node/shield_node.cc | 1 + src/ballistica/shared/ballistica.cc | 2 +- src/ballistica/shared/foundation/macros.h | 1 - src/ballistica/shared/foundation/types.h | 4 +- src/ballistica/shared/python/python_sys.h | 5 +- .../python/methods/python_methods_ui_v1.cc | 91 +++++------- src/ballistica/ui_v1/python/ui_v1_python.cc | 20 ++- src/ballistica/ui_v1/ui_v1.cc | 13 +- src/ballistica/ui_v1/ui_v1.h | 11 +- src/ballistica/ui_v1/widget/button_widget.cc | 1 + .../ui_v1/widget/container_widget.cc | 3 +- .../ui_v1/widget/container_widget.h | 101 +++++++------ .../ui_v1/widget/h_scroll_widget.cc | 1 + src/ballistica/ui_v1/widget/image_widget.cc | 2 + src/ballistica/ui_v1/widget/root_widget.cc | 17 +-- src/ballistica/ui_v1/widget/root_widget.h | 4 +- src/ballistica/ui_v1/widget/scroll_widget.cc | 1 + src/ballistica/ui_v1/widget/text_widget.cc | 2 + 66 files changed, 569 insertions(+), 350 deletions(-) diff --git a/.efrocachemap b/.efrocachemap index f4186604..46ba0042 100644 --- a/.efrocachemap +++ b/.efrocachemap @@ -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": "e5178f2851b3af9a4e38e3a7d267a240", - "build/prefab/full/linux_arm64_gui/release/ballisticakit": "912611f71c3b7d50a7e125ecede0c719", - "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "d37e2e367d558d8dc2acb0c65297e439", - "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "9d17cdce4ead349207e33ef2e1797210", - "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "7e77b7064e3d727c6774dc7b6e4d0484", - "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "c3c2386a4a8a033eaa1bd2bb30620467", - "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "ec5ef8638ab507847fe3cc70598f6467", - "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "6fef8a6f718c2ac6b322affc4fbe5dd2", - "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "d7aceacd58ddb44e8381291ba229d976", - "build/prefab/full/mac_arm64_gui/release/ballisticakit": "645725e7904049c6d5473e508e5b0a89", - "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "69ec81fbfd03210abf87ae39b45282bf", - "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "571cce7f35bceb1a2c53ca67e6d2ba66", - "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "fbfb6bbbde2ff59ac9279ac2162b2733", - "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "bb2c684f084e2bf3eb87392718b00493", - "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "5c8cc694aaca54b7d28823a7bbb99f5a", - "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "974e88892bd2ed2ac9a8c9d7cb63e38e", - "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "d19acafe6c0b7bf869976ec6b4d47250", - "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "98152c4194eaf779c2cda75e5fbd8deb", - "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "2bcd3acef687c45602a56b30d2b9541b", - "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "f7a1726e53ea787e70c57212018487b6", + "build/prefab/full/linux_arm64_gui/debug/ballisticakit": "8e1c1a6865e87aa0c5a02e65ac3bb8ec", + "build/prefab/full/linux_arm64_gui/release/ballisticakit": "25f7b1b98a98bb2a3e7b5e12362808cb", + "build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "a8573cbcbe45d27f715c25d4394a23fd", + "build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "98b5f12ea27a9af8827b768143e7edb5", + "build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "1ced073c261bb7f4cac0a54b6472b508", + "build/prefab/full/linux_x86_64_gui/release/ballisticakit": "4621ac4aa53d2babf5c67ee13f417e79", + "build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "587ac9f0678caf5d0b7479bffe50db08", + "build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "d20e0fa4d8fd8304b91fd8c3270bf499", + "build/prefab/full/mac_arm64_gui/debug/ballisticakit": "1b3aee01e605c52a6ddafdc77b701e0e", + "build/prefab/full/mac_arm64_gui/release/ballisticakit": "ed2d598a1de3249179b752b1bf3c75a8", + "build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "99e743acc7b9d8d5d849395e0ee726eb", + "build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "d774b4a8a18083262846d41f2db544ea", + "build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "cf4c11956d06b23583cfad2e946b1502", + "build/prefab/full/mac_x86_64_gui/release/ballisticakit": "38a6b5eaa4ef30f400f72b71f69cdd6e", + "build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "982a33f7b34f0a2a95a4fe072c7ad561", + "build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "dd0468ae96203b6af6529612a18e262a", + "build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "d9f152f41b712aa9969fad60d54a5dbd", + "build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "d569374c7e05a01fdd1bfb2b8f622b71", + "build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "703229ffb3bd1e0dd025225bad85d90c", + "build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "3dcf01a911a98b1d01bbd8614e8bef8f", "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": "70d97e9b1ee3aab626edaaa250ecb161", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "2cde0bcaa51f05ca76bea9f8fba23de0", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "bf044c328cb751d29a96f6f75a9a8034", - "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "26d6dc203dc2a055b393c1962a2c90e3", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "957b55aaa06ccea86893d802eda3432d", - "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "7b0dc8b1d2393700ca44a82ba00dad0c", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "100976691f6e41d024e108f5a14d55c1", - "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "679aceecd0f8d165553a6ce4f411957f", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "ad1d2ca70c9784c46fd9a079b6bfeacd", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "d239aa7f1abe82ab3920147375b5e714", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "7583533059df43d719c9b0446f282fa3", + "build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "dac29b15a3eb1294079ea002d93ec3b1", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "e19618713c795246c4aa64c455235d15", + "build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "7260b697de1753e10a7e8677c787fd16", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "b18e673dde3c97d97e74b45467fb23b0", + "build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "60abcbb58579c047ba673519a5029857", "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 04a5c26c..e75577b7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -### 1.7.37 (build 21988, api 9, 2024-09-04) +### 1.7.37 (build 21995, 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. @@ -82,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..8acb45b2 100644 --- a/src/assets/ba_data/python/babase/_app.py +++ b/src/assets/ba_data/python/babase/_app.py @@ -629,6 +629,35 @@ 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 + ) + + # Note to the user that this is currently an imperfect system. + _babase.screenmessage( + f'UI Scale is now {scale.name}.\n' + f' NOTE: some UI elements may not respond to this currently.' + ) + def _set_intent(self, intent: AppIntent) -> None: from babase._appmode import AppMode @@ -718,7 +747,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 +834,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 +883,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 +919,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 +1043,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 +1057,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 +1071,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 +1089,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..313806cb 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: @@ -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,6 +150,7 @@ class DevConsoleTabUI(DevConsoleTab): @override def refresh(self) -> None: + from babase._mgen.enums import UIScale self.text( 'UI Testing: Make sure all static UI fits in the' @@ -182,14 +183,14 @@ class DevConsoleTabUI(DevConsoleTab): ) bwidth = 100 - for sz in ('small', 'medium', 'large'): + for scale in UIScale: self.button( - sz, + scale.name, 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), ) x += bwidth + 10 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 2048568e..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 diff --git a/src/assets/ba_data/python/baenv.py b/src/assets/ba_data/python/baenv.py index 0ddf60d1..a78f15be 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 = 21988 +TARGET_BALLISTICA_BUILD = 21995 TARGET_BALLISTICA_VERSION = '1.7.37' diff --git a/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py b/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py index a5958874..5315b1a9 100644 --- a/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py +++ b/src/assets/ba_data/python/bascenev1lib/activity/coopscore.py @@ -536,7 +536,7 @@ class CoopScoreScreen(bs.Activity[bs.Player, bs.Team]): ) def _update_corner_button_positions(self) -> None: - offs = -55 if bui.is_party_icon_visible() else 0 + offs = -55 assert self._corner_button_offs is not None pos_x = self._corner_button_offs[0] + offs pos_y = self._corner_button_offs[1] 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/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/watch.py b/src/assets/ba_data/python/bauiv1lib/watch.py index d5dcb133..2db96a78 100644 --- a/src/assets/ba_data/python/bauiv1lib/watch.py +++ b/src/assets/ba_data/python/bauiv1lib/watch.py @@ -362,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..c4646e3b 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 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/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..5fa7e953 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 { @@ -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..72fb417d 100644 --- a/src/ballistica/base/ui/ui.cc +++ b/src/ballistica/base/ui/ui.cc @@ -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 fe1c0e3a..1ba94d06 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 = 21988; +const int kEngineBuildNumber = 21995; 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 765c719c..a3a397bd 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); } @@ -1628,7 +1626,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); @@ -2586,35 +2584,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* { @@ -2640,31 +2609,37 @@ 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, - }; + return {PyRootUIBackPressDef, PyGetSpecialWidgetDef, PySetPartyWindowOpenDef, + PyButtonWidgetDef, PyCheckBoxWidgetDef, PyImageWidgetDef, + PyColumnWidgetDef, PyContainerWidgetDef, PyRowWidgetDef, + PyScrollWidgetDef, PyHScrollWidgetDef, PyTextWidgetDef, + PyWidgetDef, PyUIBoundsDef, PyGetSoundDef, + PyGetTextureDef, PyGetQRCodeTextureDef, PyGetMeshDef, + PyIsAvailableDef, PyOnScreenChangeDef}; } #pragma clang diagnostic pop 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 0bc3846f..7410ab70 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 d962d6ae..8242557b 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; @@ -137,7 +131,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 a4169ad7..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" diff --git a/src/ballistica/ui_v1/widget/container_widget.cc b/src/ballistica/ui_v1/widget/container_widget.cc index a2934beb..7be644ca 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; diff --git a/src/ballistica/ui_v1/widget/container_widget.h b/src/ballistica/ui_v1/widget/container_widget.h index 5f55bd7e..88511df4 100644 --- a/src/ballistica/ui_v1/widget/container_widget.h +++ b/src/ballistica/ui_v1/widget/container_widget.h @@ -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"