Merge branch 'efroemling:main' into main

This commit is contained in:
Vishal 2024-09-06 16:09:25 +05:30 committed by GitHub
commit 7741c9ca21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
87 changed files with 860 additions and 1101 deletions

92
.efrocachemap generated
View File

@ -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",

View File

@ -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

View File

@ -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

View File

@ -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',

View File

@ -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,
)

View File

@ -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.

View File

@ -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',

View File

@ -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()

View File

@ -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)

View File

@ -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'

View File

@ -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."""

View File

@ -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',

View File

@ -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)

View File

@ -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?

View File

@ -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:

View File

@ -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)

View File

@ -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())

View File

@ -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 = (

View File

@ -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.

View File

@ -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,

View File

@ -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,
# )

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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):

View File

@ -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:

View File

@ -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)

View File

@ -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:

View File

@ -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()

View File

@ -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)

View File

@ -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

View File

@ -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.')

View File

@ -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 {

View File

@ -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

View File

@ -5,7 +5,6 @@
#include <atomic>
#include <mutex>
#include <set>
#include <string>
#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;

View File

@ -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"

View File

@ -2,6 +2,8 @@
#include "ballistica/base/graphics/component/object_component.h"
#include "ballistica/base/assets/assets.h"
namespace ballistica::base {
void ObjectComponent::WriteConfig() {

View File

@ -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) {

View File

@ -5,7 +5,12 @@
#include <vector>
#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 {

View File

@ -2,6 +2,8 @@
#include "ballistica/base/graphics/component/simple_component.h"
#include "ballistica/base/assets/assets.h"
namespace ballistica::base {
void SimpleComponent::WriteConfig() {

View File

@ -2,6 +2,8 @@
#include "ballistica/base/graphics/component/smoke_component.h"
#include "ballistica/base/assets/assets.h"
namespace ballistica::base {
void SmokeComponent::WriteConfig() {

View File

@ -2,6 +2,8 @@
#include "ballistica/base/graphics/component/sprite_component.h"
#include "ballistica/base/assets/assets.h"
namespace ballistica::base {
void SpriteComponent::WriteConfig() {

View File

@ -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<TYPE*>(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<Object::Ref<MeshDataClientHandle> >& meshes,
const std::vector<int8_t>& 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

View File

@ -7,8 +7,6 @@
#include <string>
#include <vector>
#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<Object::Ref<FramebufferObjectGL> > blur_buffers_;
std::vector<std::unique_ptr<ProgramGL> > shaders_;

View File

@ -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) {

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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();
}

View File

@ -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.

View File

@ -7,6 +7,7 @@
#include <vector>
#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"

View File

@ -5,6 +5,9 @@
#include <list>
#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 {

View File

@ -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"

View File

@ -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"

View File

@ -2,6 +2,8 @@
#include "ballistica/base/logic/logic.h"
#include <Python.h>
#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 {

View File

@ -4,9 +4,8 @@
#define BALLISTICA_BASE_LOGIC_LOGIC_H_
#include <memory>
#include <string>
#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:

View File

@ -3,6 +3,8 @@
#ifndef BALLISTICA_BASE_PYTHON_BASE_PYTHON_H_
#define BALLISTICA_BASE_PYTHON_BASE_PYTHON_H_
#include <set>
#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<std::string> do_once_locations_;

View File

@ -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<std::string> user_py_dir = g_core->GetUserPythonDirectory();
std::optional<std::string> app_py_dir = g_core->GetAppPythonDirectory();
std::optional<std::string> 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,

View File

@ -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<char**>(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<PyMethodDef> {
PyGetIdleTimeDef,
PyExtraHashValueDef,
PySetUIInputDeviceDef,
PyGetUIScaleDef,
PySetUIScaleDef,
PyGetThreadNameDef,
PySetThreadNameDef,
PyInLogicThreadDef,

View File

@ -2,6 +2,8 @@
#include "ballistica/base/ui/dev_console.h"
#include <Python.h>
#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

View File

@ -68,6 +68,8 @@ class DevConsole {
auto BaseScale() const -> float;
void RequestRefresh();
void OnUIScaleChanged();
private:
class ScopedUILock_;
class Widget_;

View File

@ -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());

View File

@ -4,11 +4,9 @@
#define BALLISTICA_BASE_UI_UI_H_
#include <string>
#include <unordered_map>
#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);

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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;

View File

@ -4,7 +4,6 @@
#define BALLISTICA_SHARED_FOUNDATION_MACROS_H_
#ifdef __cplusplus
#include <cassert>
#include <string>
#endif

View File

@ -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.
};

View File

@ -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 <Python.h>
#include <frameobject.h>
#include <weakrefobject.h>
#include <string>
#include <string> // 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

View File

@ -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<CheckBoxWidget>();
}
// 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<ScrollWidget>();
}
// 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<PyMethodDef> {
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,
};
}

View File

@ -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<base::PythonContextCall>(
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 {

View File

@ -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

View File

@ -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<ContainerWidget> screen_root_widget_;
Object::Ref<ContainerWidget> overlay_root_widget_;
Object::Ref<RootWidget> root_widget_;

View File

@ -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_;

View File

@ -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;

View File

@ -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<Object::Ref<Widget> > widgets_;
Object::Ref<base::TextureAsset> tex_;
Object::WeakRef<ButtonWidget> cancel_button_;
Object::WeakRef<ButtonWidget> 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<base::TextureAsset> 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<ButtonWidget> cancel_button_;
Object::WeakRef<ButtonWidget> 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<base::PythonContextCall> on_activate_call_;
Object::Ref<base::PythonContextCall> on_outside_click_call_;
Object::Ref<base::PythonContextCall> on_cancel_call_;

View File

@ -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"

View File

@ -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 {

View File

@ -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;

View File

@ -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:

View File

@ -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"

View File

@ -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"